Files
openlayers/src/ol/renderer/webgl/Layer.js
2018-02-15 21:39:53 -06:00

266 lines
7.0 KiB
JavaScript

/**
* @module ol/renderer/webgl/Layer
*/
import {inherits} from '../../index.js';
import RenderEvent from '../../render/Event.js';
import RenderEventType from '../../render/EventType.js';
import WebGLImmediateRenderer from '../../render/webgl/Immediate.js';
import LayerRenderer from '../Layer.js';
import {fragment, vertex} from '../webgl/defaultmapshader.js';
import Locations from '../webgl/defaultmapshader/Locations.js';
import {create as createTransform} from '../../transform.js';
import {create, fromTransform} from '../../vec/mat4.js';
import {ARRAY_BUFFER, FRAMEBUFFER, FLOAT, TEXTURE_2D,
TRIANGLE_STRIP, COLOR_ATTACHMENT0} from '../../webgl.js';
import WebGLBuffer from '../../webgl/Buffer.js';
import {createEmptyTexture} from '../../webgl/Context.js';
/**
* @constructor
* @abstract
* @extends {ol.renderer.Layer}
* @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
* @param {ol.layer.Layer} layer Layer.
*/
const WebGLLayerRenderer = function(mapRenderer, layer) {
LayerRenderer.call(this, layer);
/**
* @protected
* @type {ol.renderer.webgl.Map}
*/
this.mapRenderer = mapRenderer;
/**
* @private
* @type {ol.webgl.Buffer}
*/
this.arrayBuffer_ = new WebGLBuffer([
-1, -1, 0, 0,
1, -1, 1, 0,
-1, 1, 0, 1,
1, 1, 1, 1
]);
/**
* @protected
* @type {WebGLTexture}
*/
this.texture = null;
/**
* @protected
* @type {WebGLFramebuffer}
*/
this.framebuffer = null;
/**
* @protected
* @type {number|undefined}
*/
this.framebufferDimension = undefined;
/**
* @protected
* @type {ol.Transform}
*/
this.texCoordMatrix = createTransform();
/**
* @protected
* @type {ol.Transform}
*/
this.projectionMatrix = createTransform();
/**
* @type {Array.<number>}
* @private
*/
this.tmpMat4_ = create();
/**
* @private
* @type {ol.renderer.webgl.defaultmapshader.Locations}
*/
this.defaultLocations_ = null;
};
inherits(WebGLLayerRenderer, LayerRenderer);
/**
* @param {olx.FrameState} frameState Frame state.
* @param {number} framebufferDimension Framebuffer dimension.
* @protected
*/
WebGLLayerRenderer.prototype.bindFramebuffer = function(frameState, framebufferDimension) {
const gl = this.mapRenderer.getGL();
if (this.framebufferDimension === undefined ||
this.framebufferDimension != framebufferDimension) {
/**
* @param {WebGLRenderingContext} gl GL.
* @param {WebGLFramebuffer} framebuffer Framebuffer.
* @param {WebGLTexture} texture Texture.
*/
const postRenderFunction = function(gl, framebuffer, texture) {
if (!gl.isContextLost()) {
gl.deleteFramebuffer(framebuffer);
gl.deleteTexture(texture);
}
}.bind(null, gl, this.framebuffer, this.texture);
frameState.postRenderFunctions.push(
/** @type {ol.PostRenderFunction} */ (postRenderFunction)
);
const texture = createEmptyTexture(
gl, framebufferDimension, framebufferDimension);
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(FRAMEBUFFER,
COLOR_ATTACHMENT0, TEXTURE_2D, texture, 0);
this.texture = texture;
this.framebuffer = framebuffer;
this.framebufferDimension = framebufferDimension;
} else {
gl.bindFramebuffer(FRAMEBUFFER, this.framebuffer);
}
};
/**
* @param {olx.FrameState} frameState Frame state.
* @param {ol.LayerState} layerState Layer state.
* @param {ol.webgl.Context} context Context.
*/
WebGLLayerRenderer.prototype.composeFrame = function(frameState, layerState, context) {
this.dispatchComposeEvent_(RenderEventType.PRECOMPOSE, context, frameState);
context.bindBuffer(ARRAY_BUFFER, this.arrayBuffer_);
const gl = context.getGL();
const program = context.getProgram(fragment, vertex);
let locations;
if (!this.defaultLocations_) {
locations = new Locations(gl, program);
this.defaultLocations_ = locations;
} else {
locations = this.defaultLocations_;
}
if (context.useProgram(program)) {
gl.enableVertexAttribArray(locations.a_position);
gl.vertexAttribPointer(
locations.a_position, 2, FLOAT, false, 16, 0);
gl.enableVertexAttribArray(locations.a_texCoord);
gl.vertexAttribPointer(
locations.a_texCoord, 2, FLOAT, false, 16, 8);
gl.uniform1i(locations.u_texture, 0);
}
gl.uniformMatrix4fv(locations.u_texCoordMatrix, false,
fromTransform(this.tmpMat4_, this.getTexCoordMatrix()));
gl.uniformMatrix4fv(locations.u_projectionMatrix, false,
fromTransform(this.tmpMat4_, this.getProjectionMatrix()));
gl.uniform1f(locations.u_opacity, layerState.opacity);
gl.bindTexture(TEXTURE_2D, this.getTexture());
gl.drawArrays(TRIANGLE_STRIP, 0, 4);
this.dispatchComposeEvent_(RenderEventType.POSTCOMPOSE, context, frameState);
};
/**
* @param {ol.render.EventType} type Event type.
* @param {ol.webgl.Context} context WebGL context.
* @param {olx.FrameState} frameState Frame state.
* @private
*/
WebGLLayerRenderer.prototype.dispatchComposeEvent_ = function(type, context, frameState) {
const layer = this.getLayer();
if (layer.hasListener(type)) {
const viewState = frameState.viewState;
const resolution = viewState.resolution;
const pixelRatio = frameState.pixelRatio;
const extent = frameState.extent;
const center = viewState.center;
const rotation = viewState.rotation;
const size = frameState.size;
const render = new WebGLImmediateRenderer(
context, center, resolution, rotation, size, extent, pixelRatio);
const composeEvent = new RenderEvent(
type, render, frameState, null, context);
layer.dispatchEvent(composeEvent);
}
};
/**
* @return {!ol.Transform} Matrix.
*/
WebGLLayerRenderer.prototype.getTexCoordMatrix = function() {
return this.texCoordMatrix;
};
/**
* @return {WebGLTexture} Texture.
*/
WebGLLayerRenderer.prototype.getTexture = function() {
return this.texture;
};
/**
* @return {!ol.Transform} Matrix.
*/
WebGLLayerRenderer.prototype.getProjectionMatrix = function() {
return this.projectionMatrix;
};
/**
* Handle webglcontextlost.
*/
WebGLLayerRenderer.prototype.handleWebGLContextLost = function() {
this.texture = null;
this.framebuffer = null;
this.framebufferDimension = undefined;
};
/**
* @abstract
* @param {olx.FrameState} frameState Frame state.
* @param {ol.LayerState} layerState Layer state.
* @param {ol.webgl.Context} context Context.
* @return {boolean} whether composeFrame should be called.
*/
WebGLLayerRenderer.prototype.prepareFrame = function(frameState, layerState, context) {};
/**
* @abstract
* @param {ol.Pixel} pixel Pixel.
* @param {olx.FrameState} frameState FrameState.
* @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
* callback.
* @param {S} thisArg Value to use as `this` when executing `callback`.
* @return {T|undefined} Callback result.
* @template S,T,U
*/
WebGLLayerRenderer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {};
export default WebGLLayerRenderer;