You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
7.0 KiB
263 lines
7.0 KiB
|
3 years ago
|
/**
|
||
|
|
* @module ol/renderer/webgl/Layer
|
||
|
|
*/
|
||
|
|
import LayerProperty from '../../layer/Property.js';
|
||
|
|
import LayerRenderer from '../Layer.js';
|
||
|
|
import RenderEvent from '../../render/Event.js';
|
||
|
|
import RenderEventType from '../../render/EventType.js';
|
||
|
|
import WebGLHelper from '../../webgl/Helper.js';
|
||
|
|
import {
|
||
|
|
compose as composeTransform,
|
||
|
|
create as createTransform,
|
||
|
|
} from '../../transform.js';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @typedef {Object} PostProcessesOptions
|
||
|
|
* @property {number} [scaleRatio] Scale ratio; if < 1, the post process will render to a texture smaller than
|
||
|
|
* the main canvas that will then be sampled up (useful for saving resource on blur steps).
|
||
|
|
* @property {string} [vertexShader] Vertex shader source
|
||
|
|
* @property {string} [fragmentShader] Fragment shader source
|
||
|
|
* @property {Object<string,import("../../webgl/Helper").UniformValue>} [uniforms] Uniform definitions for the post process step
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @typedef {Object} Options
|
||
|
|
* @property {Object<string,import("../../webgl/Helper").UniformValue>} [uniforms] Uniform definitions for the post process steps
|
||
|
|
* @property {Array<PostProcessesOptions>} [postProcesses] Post-processes definitions
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @classdesc
|
||
|
|
* Base WebGL renderer class.
|
||
|
|
* Holds all logic related to data manipulation & some common rendering logic
|
||
|
|
* @template {import("../../layer/Layer.js").default} LayerType
|
||
|
|
* @extends {LayerRenderer<LayerType>}
|
||
|
|
*/
|
||
|
|
class WebGLLayerRenderer extends LayerRenderer {
|
||
|
|
/**
|
||
|
|
* @param {LayerType} layer Layer.
|
||
|
|
* @param {Options} [options] Options.
|
||
|
|
*/
|
||
|
|
constructor(layer, options) {
|
||
|
|
super(layer);
|
||
|
|
|
||
|
|
options = options || {};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The transform for viewport CSS pixels to rendered pixels. This transform is only
|
||
|
|
* set before dispatching rendering events.
|
||
|
|
* @private
|
||
|
|
* @type {import("../../transform.js").Transform}
|
||
|
|
*/
|
||
|
|
this.inversePixelTransform_ = createTransform();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @private
|
||
|
|
* @type {CanvasRenderingContext2D}
|
||
|
|
*/
|
||
|
|
this.pixelContext_ = null;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @private
|
||
|
|
*/
|
||
|
|
this.postProcesses_ = options.postProcesses;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @private
|
||
|
|
*/
|
||
|
|
this.uniforms_ = options.uniforms;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @type {WebGLHelper}
|
||
|
|
* @protected
|
||
|
|
*/
|
||
|
|
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("../../Map.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("../../Map.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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Reset options (only handles uniforms).
|
||
|
|
* @param {Options} options Options.
|
||
|
|
*/
|
||
|
|
reset(options) {
|
||
|
|
this.uniforms_ = options.uniforms;
|
||
|
|
if (this.helper) {
|
||
|
|
this.helper.setUniforms(this.uniforms_);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @protected
|
||
|
|
*/
|
||
|
|
removeHelper() {
|
||
|
|
if (this.helper) {
|
||
|
|
this.helper.dispose();
|
||
|
|
delete this.helper;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Determine whether renderFrame should be called.
|
||
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
||
|
|
* @return {boolean} Layer is ready to be rendered.
|
||
|
|
*/
|
||
|
|
prepareFrame(frameState) {
|
||
|
|
if (this.getLayer().getRenderSource()) {
|
||
|
|
let incrementGroup = true;
|
||
|
|
let groupNumber = -1;
|
||
|
|
let className;
|
||
|
|
for (let i = 0, ii = frameState.layerStatesArray.length; i < ii; i++) {
|
||
|
|
const layer = frameState.layerStatesArray[i].layer;
|
||
|
|
const renderer = layer.getRenderer();
|
||
|
|
if (!(renderer instanceof WebGLLayerRenderer)) {
|
||
|
|
incrementGroup = true;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const layerClassName = layer.getClassName();
|
||
|
|
if (incrementGroup || layerClassName !== className) {
|
||
|
|
groupNumber += 1;
|
||
|
|
incrementGroup = false;
|
||
|
|
}
|
||
|
|
className = layerClassName;
|
||
|
|
if (renderer === this) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const canvasCacheKey =
|
||
|
|
'map/' + frameState.mapId + '/group/' + groupNumber;
|
||
|
|
|
||
|
|
if (!this.helper || !this.helper.canvasCacheKeyMatches(canvasCacheKey)) {
|
||
|
|
this.removeHelper();
|
||
|
|
|
||
|
|
this.helper = new WebGLHelper({
|
||
|
|
postProcesses: this.postProcesses_,
|
||
|
|
uniforms: this.uniforms_,
|
||
|
|
canvasCacheKey: canvasCacheKey,
|
||
|
|
});
|
||
|
|
|
||
|
|
if (className) {
|
||
|
|
this.helper.getCanvas().className = className;
|
||
|
|
}
|
||
|
|
|
||
|
|
this.afterHelperCreated();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return this.prepareFrameInternal(frameState);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @protected
|
||
|
|
*/
|
||
|
|
afterHelperCreated() {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Determine whether renderFrame should be called.
|
||
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
||
|
|
* @return {boolean} Layer is ready to be rendered.
|
||
|
|
* @protected
|
||
|
|
*/
|
||
|
|
prepareFrameInternal(frameState) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Clean up.
|
||
|
|
*/
|
||
|
|
disposeInternal() {
|
||
|
|
this.removeHelper();
|
||
|
|
super.disposeInternal();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param {import("../../render/EventType.js").default} type Event type.
|
||
|
|
* @param {WebGLRenderingContext} context The rendering context.
|
||
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
||
|
|
* @private
|
||
|
|
*/
|
||
|
|
dispatchRenderEvent_(type, context, frameState) {
|
||
|
|
const layer = this.getLayer();
|
||
|
|
if (layer.hasListener(type)) {
|
||
|
|
composeTransform(
|
||
|
|
this.inversePixelTransform_,
|
||
|
|
0,
|
||
|
|
0,
|
||
|
|
frameState.pixelRatio,
|
||
|
|
-frameState.pixelRatio,
|
||
|
|
0,
|
||
|
|
0,
|
||
|
|
-frameState.size[1]
|
||
|
|
);
|
||
|
|
|
||
|
|
const event = new RenderEvent(
|
||
|
|
type,
|
||
|
|
this.inversePixelTransform_,
|
||
|
|
frameState,
|
||
|
|
context
|
||
|
|
);
|
||
|
|
layer.dispatchEvent(event);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param {WebGLRenderingContext} context The rendering context.
|
||
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
||
|
|
* @protected
|
||
|
|
*/
|
||
|
|
preRender(context, frameState) {
|
||
|
|
this.dispatchRenderEvent_(RenderEventType.PRERENDER, context, frameState);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param {WebGLRenderingContext} context The rendering context.
|
||
|
|
* @param {import("../../Map.js").FrameState} frameState Frame state.
|
||
|
|
* @protected
|
||
|
|
*/
|
||
|
|
postRender(context, frameState) {
|
||
|
|
this.dispatchRenderEvent_(RenderEventType.POSTRENDER, context, frameState);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export default WebGLLayerRenderer;
|