diff --git a/src/ol/renderer/webgl/Layer.js b/src/ol/renderer/webgl/Layer.js new file mode 100644 index 0000000000..e18733b7af --- /dev/null +++ b/src/ol/renderer/webgl/Layer.js @@ -0,0 +1,74 @@ +/** + * @module ol/renderer/webgl/Layer + */ +import LayerRenderer from '../Layer.js'; +import WebGLHelper from '../../webgl/Helper'; + + +/** + * @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.} [uniforms] Uniform definitions for the post process step + */ + +/** + * @typedef {Object} Options + * @property {Object.} [uniforms] Uniform definitions for the post process steps + * @property {Array} [postProcesses] Post-processes definitions + */ + +/** + * @classdesc + * Base WebGL renderer class. + * Holds all logic related to data manipulation & some common rendering logic + */ +class WebGLLayerRenderer extends LayerRenderer { + + /** + * @param {import("../../layer/Layer.js").default} layer Layer. + * @param {Options=} [opt_options] Options. + */ + constructor(layer, opt_options) { + super(layer); + + const options = opt_options || {}; + + this.helper_ = new WebGLHelper({ + postProcesses: options.postProcesses, + uniforms: options.uniforms + }); + } + + /** + * @inheritDoc + */ + disposeInternal() { + super.disposeInternal(); + } + + /** + * Will return the last shader compilation errors. If no error happened, will return null; + * @return {string|null} Errors, or null if last compilation was successful + * @api + */ + getShaderCompileErrors() { + return this.helper_.getShaderCompileErrors(); + } +} + +/** + * Returns a texture of 1x1 pixel, white + * @private + * @return {ImageData} Image data. + */ +export function getBlankTexture() { + const canvas = document.createElement('canvas'); + const image = canvas.getContext('2d').createImageData(1, 1); + image.data[0] = image.data[1] = image.data[2] = image.data[3] = 255; + return image; +} + +export default WebGLLayerRenderer; diff --git a/src/ol/renderer/webgl/PointsLayer.js b/src/ol/renderer/webgl/PointsLayer.js index 37dbc27830..6e5552af38 100644 --- a/src/ol/renderer/webgl/PointsLayer.js +++ b/src/ol/renderer/webgl/PointsLayer.js @@ -1,11 +1,11 @@ /** * @module ol/renderer/webgl/PointsLayer */ -import LayerRenderer from '../Layer'; import WebGLArrayBuffer from '../../webgl/Buffer'; import {DYNAMIC_DRAW, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, FLOAT} from '../../webgl'; -import WebGLHelper, {DefaultAttrib} from '../../webgl/Helper'; +import {DefaultAttrib} from '../../webgl/Helper'; import GeometryType from '../../geom/GeometryType'; +import WebGLLayerRenderer, {getBlankTexture} from './Layer'; const VERTEX_SHADER = ` precision mediump float; @@ -55,15 +55,6 @@ const FRAGMENT_SHADER = ` gl_FragColor.rgb *= gl_FragColor.a; }`; -/** - * @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.} [uniforms] Uniform definitions for the post process step - */ - /** * @typedef {Object} Options * @property {function(import("../../Feature").default):number} [sizeCallback] Will be called on every feature in the @@ -91,7 +82,7 @@ const FRAGMENT_SHADER = ` * @property {string} [fragmentShader] Fragment shader source * @property {Object.} [uniforms] Uniform definitions for the post process steps * Please note that `u_texture` is reserved for the main texture slot. - * @property {Array} [postProcesses] Post-processes definitions + * @property {Array} [postProcesses] Post-processes definitions */ /** @@ -186,22 +177,22 @@ const FRAGMENT_SHADER = ` * * @api */ -class WebGLPointsLayerRenderer extends LayerRenderer { +class WebGLPointsLayerRenderer extends WebGLLayerRenderer { /** * @param {import("../../layer/Vector.js").default} vectorLayer Vector layer. * @param {Options=} [opt_options] Options. */ constructor(vectorLayer, opt_options) { - super(vectorLayer); - const options = opt_options || {}; + // assign the `texture` uniform if not specified in the options const uniforms = options.uniforms || {}; - uniforms.u_texture = options.texture || this.getDefaultTexture(); - this.helper_ = new WebGLHelper({ - postProcesses: options.postProcesses, - uniforms: uniforms + uniforms.u_texture = options.texture || getBlankTexture(); + + super(vectorLayer, { + uniforms: uniforms, + postProcesses: options.postProcesses }); this.sourceRevision_ = -1; @@ -335,27 +326,6 @@ class WebGLPointsLayerRenderer extends LayerRenderer { return true; } - - /** - * Will return the last shader compilation errors. If no error happened, will return null; - * @return {string|null} Errors, or null if last compilation was successful - * @api - */ - getShaderCompileErrors() { - return this.helper_.getShaderCompileErrors(); - } - - /** - * Returns a texture of 1x1 pixel, white - * @private - * @return {ImageData} Image data. - */ - getDefaultTexture() { - const canvas = document.createElement('canvas'); - const image = canvas.getContext('2d').createImageData(1, 1); - image.data[0] = image.data[1] = image.data[2] = image.data[3] = 255; - return image; - } } export default WebGLPointsLayerRenderer; diff --git a/test/spec/ol/renderer/webgl/layer.test.js b/test/spec/ol/renderer/webgl/layer.test.js new file mode 100644 index 0000000000..06787c6fcd --- /dev/null +++ b/test/spec/ol/renderer/webgl/layer.test.js @@ -0,0 +1,45 @@ +import VectorLayer from '../../../../../src/ol/layer/Vector.js'; +import VectorSource from '../../../../../src/ol/source/Vector.js'; +import WebGLLayerRenderer, {getBlankTexture} from '../../../../../src/ol/renderer/webgl/Layer'; + + +describe('ol.renderer.webgl.Layer', function() { + + describe('constructor', function() { + + let target; + + beforeEach(function () { + target = document.createElement('div'); + target.style.width = '256px'; + target.style.height = '256px'; + document.body.appendChild(target); + }); + + afterEach(function () { + document.body.removeChild(target); + }); + + it('creates a new instance', function () { + const layer = new VectorLayer({ + source: new VectorSource() + }); + const renderer = new WebGLLayerRenderer(layer); + expect(renderer).to.be.a(WebGLLayerRenderer); + }); + + }); + + describe('getBlankTexture', function() { + it('creates a 1x1 white texture', function() { + const texture = getBlankTexture(); + expect(texture.height).to.eql(1); + expect(texture.width).to.eql(1); + expect(texture.data[0]).to.eql(255); + expect(texture.data[1]).to.eql(255); + expect(texture.data[2]).to.eql(255); + expect(texture.data[3]).to.eql(255); + }); + }); + +});