Dispatch precompose and postcompose events for WebGL layers
This commit is contained in:
@@ -21,16 +21,18 @@ export default {
|
||||
POSTRENDER: 'postrender',
|
||||
|
||||
/**
|
||||
* Triggered before layers are rendered.
|
||||
* The event object will not have a `context` set.
|
||||
* Triggered before layers are composed. When dispatched by the map, the event object will not have
|
||||
* a `context` set. When dispatched by a layer, the event object will have a `context` set. Only
|
||||
* WebGL layers currently dispatch this event.
|
||||
* @event module:ol/render/Event~RenderEvent#precompose
|
||||
* @api
|
||||
*/
|
||||
PRECOMPOSE: 'precompose',
|
||||
|
||||
/**
|
||||
* Triggered after all layers are rendered.
|
||||
* The event object will not have a `context` set.
|
||||
* Triggered after layers are composed. When dispatched by the map, the event object will not have
|
||||
* a `context` set. When dispatched by a layer, the event object will have a `context` set. Only
|
||||
* WebGL layers currently dispatch this event.
|
||||
* @event module:ol/render/Event~RenderEvent#postcompose
|
||||
* @api
|
||||
*/
|
||||
|
||||
@@ -88,6 +88,45 @@ class WebGLLayerRenderer extends LayerRenderer {
|
||||
this.helper;
|
||||
|
||||
layer.addChangeListener(LayerProperty.MAP, this.removeHelper_.bind(this));
|
||||
|
||||
this.dispatchPreComposeEvent = this.dispatchPreComposeEvent.bind(this);
|
||||
this.dispatchPostComposeEvent = this.dispatchPostComposeEvent.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {WebGLRenderingContext} context The WebGL rendering context.
|
||||
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @protected
|
||||
*/
|
||||
dispatchPreComposeEvent(context, frameState) {
|
||||
const layer = this.getLayer();
|
||||
if (layer.hasListener(RenderEventType.PRECOMPOSE)) {
|
||||
const event = new RenderEvent(
|
||||
RenderEventType.PRECOMPOSE,
|
||||
undefined,
|
||||
frameState,
|
||||
context
|
||||
);
|
||||
layer.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {WebGLRenderingContext} context The WebGL rendering context.
|
||||
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @protected
|
||||
*/
|
||||
dispatchPostComposeEvent(context, frameState) {
|
||||
const layer = this.getLayer();
|
||||
if (layer.hasListener(RenderEventType.POSTCOMPOSE)) {
|
||||
const event = new RenderEvent(
|
||||
RenderEventType.POSTCOMPOSE,
|
||||
undefined,
|
||||
frameState,
|
||||
context
|
||||
);
|
||||
layer.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -450,7 +450,11 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
|
||||
const renderCount = this.indicesBuffer_.getSize();
|
||||
this.helper.drawElements(0, renderCount);
|
||||
this.helper.finalizeDraw(frameState);
|
||||
this.helper.finalizeDraw(
|
||||
frameState,
|
||||
this.dispatchPreComposeEvent,
|
||||
this.dispatchPostComposeEvent
|
||||
);
|
||||
const canvas = this.helper.getCanvas();
|
||||
|
||||
if (this.hitDetectionEnabled_) {
|
||||
|
||||
@@ -552,7 +552,11 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
this.helper.finalizeDraw(frameState);
|
||||
this.helper.finalizeDraw(
|
||||
frameState,
|
||||
this.dispatchPreComposeEvent,
|
||||
this.dispatchPostComposeEvent
|
||||
);
|
||||
|
||||
const canvas = this.helper.getCanvas();
|
||||
|
||||
|
||||
@@ -637,15 +637,25 @@ class WebGLHelper extends Disposable {
|
||||
/**
|
||||
* Apply the successive post process passes which will eventually render to the actual canvas.
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState current frame state
|
||||
* @api
|
||||
* @param {function(WebGLRenderingContext, import("../PluggableMap.js").FrameState):void} [preCompose] Called before composing.
|
||||
* @param {function(WebGLRenderingContext, import("../PluggableMap.js").FrameState):void} [postCompose] Called before composing.
|
||||
*/
|
||||
finalizeDraw(frameState) {
|
||||
finalizeDraw(frameState, preCompose, postCompose) {
|
||||
// apply post processes using the next one as target
|
||||
for (let i = 0; i < this.postProcessPasses_.length; i++) {
|
||||
for (let i = 0, ii = this.postProcessPasses_.length; i < ii; i++) {
|
||||
if (i === ii - 1) {
|
||||
this.postProcessPasses_[i].apply(
|
||||
frameState,
|
||||
this.postProcessPasses_[i + 1] || null
|
||||
null,
|
||||
preCompose,
|
||||
postCompose
|
||||
);
|
||||
} else {
|
||||
this.postProcessPasses_[i].apply(
|
||||
frameState,
|
||||
this.postProcessPasses_[i + 1]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,9 +250,11 @@ class WebGLPostProcessingPass {
|
||||
* Render to the next postprocessing pass (or to the canvas if final pass).
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState current frame state
|
||||
* @param {WebGLPostProcessingPass} [nextPass] Next pass, optional
|
||||
* @param {function(WebGLRenderingContext, import("../PluggableMap.js").FrameState):void} [preCompose] Called before composing.
|
||||
* @param {function(WebGLRenderingContext, import("../PluggableMap.js").FrameState):void} [postCompose] Called before composing.
|
||||
* @api
|
||||
*/
|
||||
apply(frameState, nextPass) {
|
||||
apply(frameState, nextPass, preCompose, postCompose) {
|
||||
const gl = this.getGL();
|
||||
const size = frameState.size;
|
||||
|
||||
@@ -288,7 +290,13 @@ class WebGLPostProcessingPass {
|
||||
|
||||
this.applyUniforms(frameState);
|
||||
|
||||
if (preCompose) {
|
||||
preCompose(gl, frameState);
|
||||
}
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
if (postCompose) {
|
||||
postCompose(gl, frameState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -257,6 +257,21 @@ describe('ol/layer/WebGLTile', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('dispatches a precompose event with WebGL context', (done) => {
|
||||
let called = false;
|
||||
layer.on('precompose', (event) => {
|
||||
expect(event.context).to.be.a(WebGLRenderingContext);
|
||||
called = true;
|
||||
});
|
||||
|
||||
map.once('rendercomplete', () => {
|
||||
expect(called).to.be(true);
|
||||
done();
|
||||
});
|
||||
|
||||
map.render();
|
||||
});
|
||||
|
||||
it('dispatches a prerender event with WebGL context and inverse pixel transform', (done) => {
|
||||
let called = false;
|
||||
layer.on('prerender', (event) => {
|
||||
|
||||
BIN
test/rendering/cases/webgl-precompose-event/expected.png
Normal file
BIN
test/rendering/cases/webgl-precompose-event/expected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 910 B |
80
test/rendering/cases/webgl-precompose-event/main.js
Normal file
80
test/rendering/cases/webgl-precompose-event/main.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import DataTileSource from '../../../../src/ol/source/DataTile.js';
|
||||
import Map from '../../../../src/ol/Map.js';
|
||||
import TileLayer from '../../../../src/ol/layer/WebGLTile.js';
|
||||
import View from '../../../../src/ol/View.js';
|
||||
|
||||
const high = new Uint8Array(256 * 256).fill(255);
|
||||
const low = new Uint8Array(256 * 256).fill(0);
|
||||
|
||||
const red = new TileLayer({
|
||||
transition: 0,
|
||||
source: new DataTileSource({
|
||||
minZoom: 2,
|
||||
loader: function (z, x, y) {
|
||||
if ((x + y) % 2 === 0) {
|
||||
return high;
|
||||
}
|
||||
return low;
|
||||
},
|
||||
}),
|
||||
style: {
|
||||
color: ['array', ['band', 1], 0, 0, 1],
|
||||
},
|
||||
});
|
||||
|
||||
const green = new TileLayer({
|
||||
transition: 0,
|
||||
source: new DataTileSource({
|
||||
minZoom: 2,
|
||||
loader: (z, x) => {
|
||||
if (x % 2 === 0) {
|
||||
return high;
|
||||
}
|
||||
return low;
|
||||
},
|
||||
}),
|
||||
style: {
|
||||
color: ['array', 0, ['band', 1], 0, 1],
|
||||
},
|
||||
});
|
||||
|
||||
green.on('precompose', (event) => {
|
||||
const gl = event.context;
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFunc(gl.ONE, gl.ONE);
|
||||
});
|
||||
|
||||
const blue = new TileLayer({
|
||||
transition: 0,
|
||||
source: new DataTileSource({
|
||||
minZoom: 2,
|
||||
loader: (z, x, y) => {
|
||||
if (y % 2 === 0) {
|
||||
return high;
|
||||
}
|
||||
return low;
|
||||
},
|
||||
}),
|
||||
style: {
|
||||
color: ['array', 0, 0, ['band', 1], 1],
|
||||
},
|
||||
});
|
||||
|
||||
blue.on('precompose', (event) => {
|
||||
const gl = event.context;
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFunc(gl.ONE, gl.ONE);
|
||||
});
|
||||
|
||||
new Map({
|
||||
target: 'map',
|
||||
layers: [red, green, blue],
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 0,
|
||||
}),
|
||||
});
|
||||
|
||||
render({
|
||||
message: 'precompose events can be used to change layer blending',
|
||||
});
|
||||
Reference in New Issue
Block a user