Add initial WebGL renderer skeleton
This commit is contained in:
@@ -8,6 +8,9 @@ goog.require('ol.renderer.MapRenderer');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.Loc');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('goog.webgl');
|
||||
|
||||
/**
|
||||
@@ -17,13 +20,13 @@ goog.require('goog.webgl');
|
||||
* @extends {ol.renderer.MapRenderer}
|
||||
*/
|
||||
ol.renderer.WebGL = function(target) {
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Element}
|
||||
*/
|
||||
this.canvas_ = goog.dom.createDom('canvas', 'ol-renderer-webgl-canvas'); // Suppose to have: style: 'width:100%;height:100%;'
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {WebGLRenderingContext}
|
||||
@@ -36,28 +39,92 @@ ol.renderer.WebGL = function(target) {
|
||||
'preserveDrawingBuffer': false
|
||||
}));
|
||||
goog.asserts.assert(!goog.isNull(this.gl_), "The WebGL is not supported on your browser. Check http://get.webgl.org/");
|
||||
var gl = this.gl_;
|
||||
|
||||
goog.dom.append(target, this.canvas_);
|
||||
|
||||
goog.base(this, target);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, WebGLTexture>}
|
||||
*/
|
||||
this.textureCache_ = {};
|
||||
|
||||
var gl = this.gl_;
|
||||
|
||||
var clearColor = [0, 0, 0]; // hardcoded background color
|
||||
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], 1);
|
||||
gl.disable(goog.webgl.DEPTH_TEST);
|
||||
gl.disable(goog.webgl.SCISSOR_TEST);
|
||||
gl.disable(goog.webgl.CULL_FACE);
|
||||
|
||||
goog.base(this, target);
|
||||
|
||||
/**
|
||||
* @type Array.<ol.renderer.LayerRenderer>
|
||||
* @private
|
||||
*/
|
||||
this.renderers_ = [];
|
||||
|
||||
var fragmentShader = gl.createShader(goog.webgl.FRAGMENT_SHADER);
|
||||
gl.shaderSource(fragmentShader, [
|
||||
'precision mediump float;',
|
||||
'',
|
||||
'uniform sampler2D uTexture;',
|
||||
'',
|
||||
'varying vec2 vTexCoord;',
|
||||
'',
|
||||
'void main(void) {',
|
||||
' gl_FragColor = vec4(vec3(texture2D(uTexture, vTexCoord)), 1.);',
|
||||
'}'
|
||||
].join('\n'));
|
||||
gl.compileShader(fragmentShader);
|
||||
if (!gl.getShaderParameter(fragmentShader, goog.webgl.COMPILE_STATUS)) {
|
||||
window.console.log(gl.getShaderInfoLog(fragmentShader));
|
||||
goog.asserts.assert(gl.getShaderParameter(fragmentShader, goog.webgl.COMPILE_STATUS));
|
||||
}
|
||||
|
||||
var vertexShader = gl.createShader(goog.webgl.VERTEX_SHADER);
|
||||
gl.shaderSource(vertexShader, [
|
||||
'attribute vec2 aPosition;',
|
||||
'attribute vec2 aTexCoord;',
|
||||
'',
|
||||
'uniform mat4 uMVPMatrix;',
|
||||
'',
|
||||
'varying vec2 vTexCoord;',
|
||||
'',
|
||||
'void main(void) {',
|
||||
' gl_Position = uMVPMatrix * vec4(aPosition, 0.0, 1.0);',
|
||||
' vTexCoord = aTexCoord;',
|
||||
'}'
|
||||
].join('\n'));
|
||||
if (!gl.getShaderParameter(vertexShader, goog.webgl.COMPILE_STATUS)) {
|
||||
window.console.log(gl.getShaderInfoLog(vertexShader));
|
||||
goog.asserts.assert(gl.getShaderParameter(vertexShader, goog.webgl.COMPILE_STATUS));
|
||||
}
|
||||
|
||||
var program = gl.createProgram();
|
||||
gl.attachShader(program, fragmentShader);
|
||||
gl.attachShader(program, vertexShader);
|
||||
gl.linkProgram(program);
|
||||
if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS)) {
|
||||
window.console.log(gl.getProgramInfoLog(program));
|
||||
goog.asserts.assert(gl.getProgramParameter(program, goog.webgl.LINK_STATUS));
|
||||
}
|
||||
|
||||
this.mvpMatrixLocation_ = gl.getUniformLocation(program, 'uMVPMatrix');
|
||||
this.textureLocation_ = gl.getUniformLocation(program, 'uTexture');
|
||||
|
||||
var texCoordBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(goog.webgl.ARRAY_BUFFER, texCoordBuffer);
|
||||
gl.bufferData(goog.webgl.ARRAY_BUFFER, new Float32Array([0, 1, 1, 1, 0, 0, 1, 0]), goog.webgl.STATIC_DRAW);
|
||||
var texCoordLocation = gl.getAttributeLocation(program, 'aTexCoord');
|
||||
gl.enableVertexAttribArray(texCoordLocation);
|
||||
gl.vertexAttribPointer(texCoordLocation, 2, goog.webgl.FLOAT, false, 0, 0);
|
||||
gl.bindBuffer(goog.webgl.ARRAY_BUFFER, null);
|
||||
|
||||
this.positionLocation_ = gl.getAttributeLocation(program, 'aPosition');
|
||||
gl.enableVertexAttribArray(this.positionLocation_);
|
||||
this.positionBuffer_ = gl.createBuffer();
|
||||
|
||||
};
|
||||
|
||||
goog.inherits(ol.renderer.WebGL, ol.renderer.MapRenderer);
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Determine if this renderer type is supported in this environment.
|
||||
* A static method.
|
||||
* @returns {boolean} This renderer is supported.
|
||||
@@ -66,80 +133,136 @@ ol.renderer.WebGL.isSupported = function() {
|
||||
return !goog.isNull( goog.dom.createDom('canvas').getContext('experimental-webgl') );
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.layer.Layer>} layers
|
||||
* @param {ol.Loc} center
|
||||
* @param {number} resolution
|
||||
*/
|
||||
ol.renderer.WebGL.prototype.draw = function(layers, center, resolution) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Layer} layer
|
||||
* @param {ol.Tile} tile Tile.
|
||||
* @protected
|
||||
*/
|
||||
ol.renderer.WebGL.prototype.getRenderer = function(layer) {
|
||||
function finder(candidate) {
|
||||
return candidate.getLayer() === layer;
|
||||
ol.renderer.WebGL.prototype.bindTexture = function(tile) {
|
||||
var gl = this.gl_;
|
||||
var url = tile.getUrl();
|
||||
if (url in this.textureCache_) {
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.textureCache_[url]);
|
||||
} else {
|
||||
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, tile.getImg());
|
||||
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);
|
||||
this.textureCache_[url] = texture;
|
||||
}
|
||||
return goog.array.find(this.renderers_, finder);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Layer} layer
|
||||
* @param {ol.Tile} tile Tile.
|
||||
* @protected
|
||||
*/
|
||||
ol.renderer.WebGL.prototype.createRenderer = function(layer) {
|
||||
ol.renderer.WebGL.prototype.handleTileLoad = function(tile) {
|
||||
this.redraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* List of preferred renderer types. Layer renderers have a getType method
|
||||
* that returns a string describing their type. This list determines the
|
||||
* preferences for picking a layer renderer.
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
ol.renderer.WebGL.preferredRenderers = ["svg", "canvas", "vml"];
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Layer} layer
|
||||
* @returns {Function}
|
||||
* @param {ol.Tile} tile Tile.
|
||||
* @protected
|
||||
*/
|
||||
ol.renderer.WebGL.prototype.pickRendererType = function(layer) {
|
||||
// maps candidate renderer types to candidate renderers
|
||||
var types = {};
|
||||
ol.renderer.WebGL.prototype.handleTileDestroy = function(tile) {
|
||||
var gl = this.gl_;
|
||||
var url = tile.getUrl();
|
||||
if (url in this.textureCache_) {
|
||||
gl.deleteTexture(this.textureCache_[url]);
|
||||
delete this.textureCache_[url];
|
||||
}
|
||||
};
|
||||
|
||||
function picker(Candidate) {
|
||||
var supports = Candidate.isSupported() && Candidate.canRender(layer);
|
||||
if (supports) {
|
||||
types[Candidate.getType()] = Candidate;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.WebGL.prototype.draw = function(layers, center, resolution, animate) {
|
||||
|
||||
var gl = this.gl_;
|
||||
|
||||
var width = this.canvas_.width;
|
||||
var height = this.canvas_.height;
|
||||
|
||||
var bounds = new ol.Bounds(
|
||||
center.getX() - width * resolution / 2,
|
||||
center.getY() - height * resolution / 2,
|
||||
center.getX() + width * resolution / 2,
|
||||
center.getY() + height * resolution / 2,
|
||||
center.getProjection());
|
||||
|
||||
/** @type {goog.vec.Mat4.Type} */
|
||||
var cameraMatrix;
|
||||
goog.vec.Mat4.makeIdentity(cameraMatrix);
|
||||
goog.vec.Mat4.scale(cameraMatrix, resolution, resolution, 1);
|
||||
goog.vec.Mat4.translate(cameraMatrix, -center.getX(), -center.getY(), 0);
|
||||
|
||||
/** @type {goog.vec.Mat4.Type} */
|
||||
var positionToViewportMatrix;
|
||||
goog.vec.Mat4.makeIdentity(positionToViewportMatrix);
|
||||
goog.vec.Mat4.scale(positionToViewportMatrix, 1 / width, 1 / height, 1);
|
||||
goog.vec.Mat4.multMat(positionToViewportMatrix, cameraMatrix, positionToViewportMatrix);
|
||||
|
||||
/** @type {goog.vec.Mat4.Type} */
|
||||
var viewportToPositionMatrix;
|
||||
var inverted = goog.vec.Mat4.invert(positionToViewportMatrix, viewportToPositionMatrix);
|
||||
goog.asserts.assert(inverted);
|
||||
|
||||
/** @type {goog.vec.Mat4.Type} */
|
||||
var targetPixelToPositionMatrix;
|
||||
goog.vec.Mat4.makeIdentity(targetPixelToPositionMatrix);
|
||||
goog.vec.Mat4.translate(targetPixelToPositionMatrix, -1, 1, 0);
|
||||
goog.vec.Mat4.scale(targetPixelToPositionMatrix, 2 / width, -2 / height, 1);
|
||||
goog.vec.Mat4.multMat(viewportToPositionMatrix, targetPixelToPositionMatrix, targetPixelToPositionMatrix);
|
||||
|
||||
gl.clear(goog.webgl.COLOR_BUFFER_BIT);
|
||||
gl.bindBuffer(goog.webgl.ARRAY_BUFFER, this.positionBuffer_);
|
||||
gl.uniform1i(this.textureLocation_, 0);
|
||||
gl.uniformMatrix4fv(this.positionLocation_, false, positionToViewportMatrix);
|
||||
|
||||
goog.array.forEach(layers, function(layer) {
|
||||
if (!(layer instanceof ol.layer.TileLayer)) {
|
||||
return;
|
||||
}
|
||||
return supports;
|
||||
}
|
||||
var Candidates = goog.array.some(ol.renderer.WebGL.registry_, picker);
|
||||
|
||||
// check to see if any preferred renderers are available
|
||||
var preferences = ol.renderer.WebGL.preferredRenderers;
|
||||
|
||||
var Renderer;
|
||||
for (var i=0, ii=preferences.length; i<ii; ++i) {
|
||||
Renderer = preferences[i];
|
||||
if (Renderer) {
|
||||
break;
|
||||
var tileLayer = /** @type {ol.layer.TileLayer} */ (layer);
|
||||
var tileSet = layer.getData(bounds, resolution);
|
||||
var tiles = tileSet.getTiles();
|
||||
var i, j, row, tile, tileBounds, positions, texture;
|
||||
for (i = 0; i < tiles.length; ++i) {
|
||||
row = tiles[i];
|
||||
for (j = 0; j < row.length; ++j) {
|
||||
tile = row[j];
|
||||
if (!tile.isLoaded()) {
|
||||
continue;
|
||||
}
|
||||
tileBounds = tile.getBounds();
|
||||
positions = [
|
||||
tileBounds.getMinX(), tileBounds.getMinY(),
|
||||
tileBounds.getMaxX(), tileBounds.getMinY(),
|
||||
tileBounds.getMinX(), tileBounds.getMaxY(),
|
||||
tileBounds.getMaxX(), tileBounds.getMaxY()
|
||||
];
|
||||
gl.bufferData(goog.webgl.ARRAY_BUFFER, new Float32Array(positions), goog.webgl.DYNAMIC_DRAW);
|
||||
gl.vertexAttribPointer(this.positionLocation_, 2, goog.webgl.FLOAT, false, 0, 0);
|
||||
this.bindTexture(tile);
|
||||
gl.drawArrays(goog.webgl.TRIANGLES, 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't find any of the preferred renderers, use the first
|
||||
return Renderer || Candidates[0] || null;
|
||||
}, this);
|
||||
|
||||
this.renderedLayers_ = layers;
|
||||
this.renderedCenter_ = center;
|
||||
this.renderedResolution_ = resolution;
|
||||
this.renderedAnimate_ = animate;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {Array.<Function>}
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.WebGL.registry_ = [];
|
||||
|
||||
/**
|
||||
* @param {Function} Renderer
|
||||
*/
|
||||
ol.renderer.WebGL.register = function(Renderer) {
|
||||
ol.renderer.WebGL.registry_.push(Renderer);
|
||||
ol.renderer.WebGL.prototype.redraw = function() {
|
||||
this.draw(this.renderedLayers_, this.renderedCenter_, this.renderedResolution_, this.renderedAnimate_);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user