Merge pull request #3065 from tsauerwein/webgl-point-hit-detection

Add hit-detection support for WebGL
This commit is contained in:
Tobias Sauerwein
2015-01-22 10:19:37 +01:00
17 changed files with 609 additions and 156 deletions

View File

@@ -11,6 +11,7 @@ goog.require('ol.extent');
goog.require('ol.layer.Image');
goog.require('ol.proj');
goog.require('ol.renderer.webgl.Layer');
goog.require('ol.webgl.Context');
@@ -49,24 +50,8 @@ ol.renderer.webgl.ImageLayer.prototype.createTexture_ = function(image) {
var imageElement = image.getImage();
var gl = this.getWebGLMapRenderer().getGL();
var texture = gl.createTexture();
gl.bindTexture(goog.webgl.TEXTURE_2D, texture);
gl.texImage2D(goog.webgl.TEXTURE_2D, 0, goog.webgl.RGBA,
goog.webgl.RGBA, goog.webgl.UNSIGNED_BYTE, imageElement);
gl.texParameteri(
goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S,
goog.webgl.CLAMP_TO_EDGE);
gl.texParameteri(
goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T,
goog.webgl.CLAMP_TO_EDGE);
gl.texParameteri(
goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MIN_FILTER, goog.webgl.LINEAR);
gl.texParameteri(
goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, goog.webgl.LINEAR);
return texture;
return ol.webgl.Context.createTexture(
gl, imageElement, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE);
};

View File

@@ -11,6 +11,7 @@ goog.require('ol.renderer.Layer');
goog.require('ol.renderer.webgl.map.shader.Color');
goog.require('ol.renderer.webgl.map.shader.Default');
goog.require('ol.webgl.Buffer');
goog.require('ol.webgl.Context');
@@ -115,15 +116,8 @@ ol.renderer.webgl.Layer.prototype.bindFramebuffer =
}
}, gl, this.framebuffer, this.texture));
var texture = gl.createTexture();
gl.bindTexture(goog.webgl.TEXTURE_2D, texture);
gl.texImage2D(goog.webgl.TEXTURE_2D, 0, goog.webgl.RGBA,
framebufferDimension, framebufferDimension, 0, goog.webgl.RGBA,
goog.webgl.UNSIGNED_BYTE, null);
gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER,
goog.webgl.LINEAR);
gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MIN_FILTER,
goog.webgl.LINEAR);
var texture = ol.webgl.Context.createEmptyTexture(
gl, framebufferDimension, framebufferDimension);
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, framebuffer);

View File

@@ -290,13 +290,10 @@ ol.renderer.webgl.Map.prototype.dispatchComposeEvent_ =
replayGroup.finish(context);
if (!replayGroup.isEmpty()) {
// use default color values
var opacity = 1;
var brightness = 0;
var contrast = 1;
var hue = 0;
var saturation = 1;
var d = ol.renderer.webgl.Map.DEFAULT_COLOR_VALUES_;
replayGroup.replay(context, center, resolution, rotation, size,
pixelRatio, opacity, brightness, contrast, hue, saturation, {});
pixelRatio, d.opacity, d.brightness, d.contrast,
d.hue, d.saturation, {});
}
replayGroup.getDeleteResourcesFunction(context)();
@@ -538,3 +535,79 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
this.scheduleExpireIconCache(frameState);
};
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.forEachFeatureAtPixel =
function(coordinate, frameState, callback, thisArg,
layerFilter, thisArg2) {
var result;
if (this.getGL().isContextLost()) {
return false;
}
var context = this.getContext();
var viewState = frameState.viewState;
// do the hit-detection for the overlays first
if (!goog.isNull(this.replayGroup)) {
/** @type {Object.<string, boolean>} */
var features = {};
// use default color values
var d = ol.renderer.webgl.Map.DEFAULT_COLOR_VALUES_;
result = this.replayGroup.forEachFeatureAtPixel(context,
viewState.center, viewState.resolution, viewState.rotation,
frameState.size, frameState.pixelRatio,
d.opacity, d.brightness, d.contrast, d.hue, d.saturation, {},
coordinate,
/**
* @param {ol.Feature} feature Feature.
* @return {?} Callback result.
*/
function(feature) {
goog.asserts.assert(goog.isDef(feature));
var key = goog.getUid(feature).toString();
if (!(key in features)) {
features[key] = true;
return callback.call(thisArg, feature, null);
}
});
if (result) {
return result;
}
}
var layerStates = this.getMap().getLayerGroup().getLayerStatesArray();
var numLayers = layerStates.length;
var i;
for (i = numLayers - 1; i >= 0; --i) {
var layerState = layerStates[i];
var layer = layerState.layer;
if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
layerFilter.call(thisArg2, layer)) {
var layerRenderer = this.getLayerRenderer(layer);
result = layerRenderer.forEachFeatureAtPixel(
coordinate, frameState, callback, thisArg);
if (result) {
return result;
}
}
}
return undefined;
};
/**
* @private
*/
ol.renderer.webgl.Map.DEFAULT_COLOR_VALUES_ = {
opacity: 1,
brightness: 0,
contrast: 1,
hue: 0,
saturation: 1
};

View File

@@ -58,6 +58,13 @@ ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) {
*/
this.replayGroup_ = null;
/**
* The last layer state.
* @private
* @type {?ol.layer.LayerState}
*/
this.layerState_ = null;
};
goog.inherits(ol.renderer.webgl.VectorLayer, ol.renderer.webgl.Layer);
@@ -67,6 +74,7 @@ goog.inherits(ol.renderer.webgl.VectorLayer, ol.renderer.webgl.Layer);
*/
ol.renderer.webgl.VectorLayer.prototype.composeFrame =
function(frameState, layerState, context) {
this.layerState_ = layerState;
var viewState = frameState.viewState;
var replayGroup = this.replayGroup_;
if (!goog.isNull(replayGroup) && !replayGroup.isEmpty()) {
@@ -100,6 +108,35 @@ ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() {
*/
ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtPixel =
function(coordinate, frameState, callback, thisArg) {
if (goog.isNull(this.replayGroup_) || goog.isNull(this.layerState_)) {
return undefined;
} else {
var mapRenderer = this.getWebGLMapRenderer();
var context = mapRenderer.getContext();
var viewState = frameState.viewState;
var layer = this.getLayer();
var layerState = this.layerState_;
/** @type {Object.<string, boolean>} */
var features = {};
return this.replayGroup_.forEachFeatureAtPixel(context,
viewState.center, viewState.resolution, viewState.rotation,
frameState.size, frameState.pixelRatio,
layerState.opacity, layerState.brightness, layerState.contrast,
layerState.hue, layerState.saturation, frameState.skippedFeatureUids,
coordinate,
/**
* @param {ol.Feature} feature Feature.
* @return {?} Callback result.
*/
function(feature) {
goog.asserts.assert(goog.isDef(feature));
var key = goog.getUid(feature).toString();
if (!(key in features)) {
features[key] = true;
return callback.call(thisArg, feature, layer);
}
});
}
};
@@ -167,7 +204,7 @@ ol.renderer.webgl.VectorLayer.prototype.prepareFrame =
var replayGroup = new ol.render.webgl.ReplayGroup(
ol.renderer.vector.getTolerance(resolution, pixelRatio),
extent);
extent, vectorLayer.getRenderBuffer());
vectorSource.loadFeatures(extent, resolution, projection);
var renderFeature =
/**