Add working WebGL renderer

This commit is contained in:
Tom Payne
2012-07-22 01:14:27 +02:00
parent c82bacb762
commit 4906bdced5
2 changed files with 118 additions and 71 deletions
+14 -9
View File
@@ -39,13 +39,17 @@ ol.webgl.map.shader.Fragment = function() {
goog.base(this, [ goog.base(this, [
'precision mediump float;', 'precision mediump float;',
'', '',
'uniform mat4 uMatrix;',
'uniform float uOpacity;', 'uniform float uOpacity;',
'uniform sampler2D uTexture;', 'uniform sampler2D uTexture;',
'', '',
'varying vec2 vTexCoord;', 'varying vec2 vTexCoord;',
'', '',
'void main(void) {', 'void main(void) {',
' gl_FragColor = vec4(texture2D(uTexture, vTexCoord).rgb, uOpacity);', ' vec4 texCoord = uMatrix * vec4(vTexCoord, 0., 1.);',
' vec4 srcColor = texture2D(uTexture, texCoord.st);',
' gl_FragColor.rgb = srcColor.rgb;',
' gl_FragColor.a = srcColor.a * uOpacity;',
'}' '}'
].join('\n')); ].join('\n'));
}; };
@@ -65,10 +69,8 @@ ol.webgl.map.shader.Vertex = function() {
'', '',
'varying vec2 vTexCoord;', 'varying vec2 vTexCoord;',
'', '',
'uniform mat4 uMatrix;',
'',
'void main(void) {', 'void main(void) {',
' gl_Position = uMatrix * vec4(aPosition, 0., 1.);', ' gl_Position = vec4(aPosition, 0., 1.);',
' vTexCoord = aTexCoord;', ' vTexCoord = aTexCoord;',
'}' '}'
].join('\n')); ].join('\n'));
@@ -417,7 +419,10 @@ ol.webgl.Map.prototype.handleWebGLContextLost = function(event) {
*/ */
ol.webgl.Map.prototype.handleWebGLContextRestored = function() { ol.webgl.Map.prototype.handleWebGLContextRestored = function() {
var gl = this.gl_; var gl = this.gl_;
gl.activeTexture(goog.webgl.TEXTURE0);
gl.blendFunc(goog.webgl.SRC_ALPHA, goog.webgl.ONE_MINUS_SRC_ALPHA);
gl.disable(goog.webgl.CULL_FACE); gl.disable(goog.webgl.CULL_FACE);
gl.disable(goog.webgl.DEPTH_TEST);
gl.disable(goog.webgl.SCISSOR_TEST); gl.disable(goog.webgl.SCISSOR_TEST);
this.redraw(); this.redraw();
}; };
@@ -433,6 +438,7 @@ ol.webgl.Map.prototype.redrawInternal = function() {
if (!goog.isDef(center) || !goog.isDef(resolution)) { if (!goog.isDef(center) || !goog.isDef(resolution)) {
return false; return false;
} }
var size = this.getSize();
var animate = goog.base(this, 'redrawInternal'); var animate = goog.base(this, 'redrawInternal');
@@ -444,7 +450,7 @@ ol.webgl.Map.prototype.redrawInternal = function() {
this.clearColor_.a); this.clearColor_.a);
gl.clear(goog.webgl.COLOR_BUFFER_BIT); gl.clear(goog.webgl.COLOR_BUFFER_BIT);
gl.enable(goog.webgl.BLEND); gl.enable(goog.webgl.BLEND);
gl.blendFunc(goog.webgl.SRC_ALPHA, goog.webgl.ONE_MINUS_SRC_ALPHA); gl.viewport(0, 0, size.width, size.height);
var program = this.getProgram(this.fragmentShader_, this.vertexShader_); var program = this.getProgram(this.fragmentShader_, this.vertexShader_);
gl.useProgram(program); gl.useProgram(program);
@@ -462,9 +468,9 @@ ol.webgl.Map.prototype.redrawInternal = function() {
var arrayBuffer = gl.createBuffer(); var arrayBuffer = gl.createBuffer();
gl.bindBuffer(goog.webgl.ARRAY_BUFFER, arrayBuffer); gl.bindBuffer(goog.webgl.ARRAY_BUFFER, arrayBuffer);
gl.bufferData(goog.webgl.ARRAY_BUFFER, new Float32Array([ gl.bufferData(goog.webgl.ARRAY_BUFFER, new Float32Array([
0, 0, 0, 0, -1, -1, 0, 0,
1, 0, 1, 0, 1, -1, 1, 0,
0, 1, 0, 1, -1, 1, 0, 1,
1, 1, 1, 1 1, 1, 1, 1
]), goog.webgl.STATIC_DRAW); ]), goog.webgl.STATIC_DRAW);
this.arrayBuffer_ = arrayBuffer; this.arrayBuffer_ = arrayBuffer;
@@ -485,7 +491,6 @@ ol.webgl.Map.prototype.redrawInternal = function() {
this.locations_.uMatrix, false, layerRenderer.getMatrix()); this.locations_.uMatrix, false, layerRenderer.getMatrix());
gl.uniform1f(this.locations_.uOpacity, layer.getOpacity()); gl.uniform1f(this.locations_.uOpacity, layer.getOpacity());
gl.bindTexture(goog.webgl.TEXTURE_2D, layerRenderer.getTexture()); gl.bindTexture(goog.webgl.TEXTURE_2D, layerRenderer.getTexture());
gl.activeTexture(goog.webgl.TEXTURE0);
gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4);
}, this); }, this);
+104 -62
View File
@@ -30,7 +30,7 @@ ol.webgl.tilelayerrenderer.shader.Fragment = function() {
'varying vec2 vTexCoord;', 'varying vec2 vTexCoord;',
'', '',
'void main(void) {', 'void main(void) {',
' gl_FragColor = vec4(texture2D(uTexture, vTexCoord).rgb, 1.);', ' gl_FragColor = texture2D(uTexture, vTexCoord);',
'}' '}'
].join('\n')); ].join('\n'));
}; };
@@ -123,9 +123,9 @@ ol.webgl.TileLayerRenderer = function(map, tileLayer) {
/** /**
* @private * @private
* @type {ol.Size} * @type {number|undefined}
*/ */
this.framebufferSize_ = null; this.framebufferDimension_ = undefined;
/** /**
* @private * @private
@@ -137,12 +137,62 @@ ol.webgl.TileLayerRenderer = function(map, tileLayer) {
* @private * @private
* @type {goog.vec.Mat4.AnyType} * @type {goog.vec.Mat4.AnyType}
*/ */
this.matrix_ = goog.vec.Mat4.createFloat32(); this.matrix_ = goog.vec.Mat4.createNumber();
}; };
goog.inherits(ol.webgl.TileLayerRenderer, ol.webgl.LayerRenderer); goog.inherits(ol.webgl.TileLayerRenderer, ol.webgl.LayerRenderer);
/**
* @param {number} framebufferDimension Framebuffer dimension.
* @private
*/
ol.webgl.TileLayerRenderer.prototype.bindFramebuffer_ =
function(framebufferDimension) {
var gl = this.getGL();
if (!goog.isDef(this.framebufferDimension_) ||
this.framebufferDimension_ != framebufferDimension) {
gl.deleteFramebuffer(this.framebuffer_);
gl.deleteRenderbuffer(this.renderbuffer_);
gl.deleteTexture(this.texture_);
var texture = gl.createTexture();
gl.bindTexture(goog.webgl.TEXTURE_2D, texture);
gl.texImage2D(goog.webgl.TEXTURE_2D, 0, gl.RGBA, framebufferDimension,
framebufferDimension, 0, goog.webgl.RGBA, goog.webgl.UNSIGNED_BYTE,
null);
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);
var renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(goog.webgl.RENDERBUFFER, renderbuffer);
gl.renderbufferStorage(goog.webgl.RENDERBUFFER,
goog.webgl.DEPTH_COMPONENT16, framebufferDimension,
framebufferDimension);
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(goog.webgl.FRAMEBUFFER,
goog.webgl.COLOR_ATTACHMENT0, goog.webgl.TEXTURE_2D, texture, 0);
gl.framebufferRenderbuffer(goog.webgl.FRAMEBUFFER,
goog.webgl.DEPTH_ATTACHMENT, goog.webgl.RENDERBUFFER, renderbuffer);
this.texture_ = texture;
this.renderbuffer_ = renderbuffer;
this.framebuffer_ = framebuffer;
this.framebufferDimension_ = framebufferDimension;
} else {
gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, this.framebuffer_);
}
};
/** /**
* @return {ol.TileLayer} Layer. * @return {ol.TileLayer} Layer.
* @override * @override
@@ -199,7 +249,7 @@ ol.webgl.TileLayerRenderer.prototype.handleWebGLContextLost = function() {
this.texture_ = null; this.texture_ = null;
this.renderbuffer_ = null; this.renderbuffer_ = null;
this.framebuffer_ = null; this.framebuffer_ = null;
this.framebufferSize_ = null; this.framebufferDimension_ = undefined;
}; };
@@ -219,60 +269,37 @@ ol.webgl.TileLayerRenderer.prototype.redraw = function() {
var gl = this.getGL(); var gl = this.getGL();
var map = this.getMap(); var map = this.getMap();
var center = /** @type {!ol.Coordinate} */ map.getCenter(); var mapExtent = /** @type {!ol.Extent} */ map.getExtent();
var extent = /** @type {!ol.Extent} */ map.getExtent(); var mapResolution = /** @type {number} */ map.getResolution();
var resolution = /** @type {number} */ map.getResolution(); var mapSize = map.getSize();
var tileLayer = this.getLayer(); var tileLayer = this.getLayer();
var tileStore = tileLayer.getStore(); var tileStore = tileLayer.getStore();
var tileGrid = tileStore.getTileGrid(); var tileGrid = tileStore.getTileGrid();
var z = tileGrid.getZForResolution(resolution); var z = tileGrid.getZForResolution(mapResolution);
var tileBounds = tileGrid.getTileBoundsForExtentAndZ(extent, z); var tileBounds = tileGrid.getTileBoundsForExtentAndZ(mapExtent, z);
var tileBoundsSize = tileBounds.getSize(); var tileBoundsSize = tileBounds.getSize();
var tileSize = tileGrid.getTileSize(); var tileSize = tileGrid.getTileSize();
var framebufferSize = new ol.Size( var maxDimension = Math.max(
tileSize.width * tileBoundsSize.width, tileBoundsSize.width * tileSize.width,
tileSize.height * tileBoundsSize.height); tileBoundsSize.height * tileSize.height);
// FIXME find a better algorithms for rounding up to the next power of two
if (goog.isNull(this.framebufferSize_) || var framebufferDimension = Math.max(tileSize.width, tileSize.height);
!this.framebufferSize_.equals(framebufferSize)) { while (framebufferDimension < maxDimension) {
framebufferDimension *= 2;
gl.deleteFramebuffer(this.framebuffer_);
gl.deleteRenderbuffer(this.renderbuffer_);
gl.deleteTexture(this.texture_);
var texture = gl.createTexture();
gl.bindTexture(goog.webgl.TEXTURE_2D, texture);
gl.texImage2D(goog.webgl.TEXTURE_2D, 0, gl.RGBA, framebufferSize.width,
framebufferSize.height, 0, goog.webgl.RGBA, goog.webgl.UNSIGNED_BYTE,
null);
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);
var renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(goog.webgl.RENDERBUFFER, renderbuffer);
gl.renderbufferStorage(goog.webgl.RENDERBUFFER,
goog.webgl.DEPTH_COMPONENT16, framebufferSize.width,
framebufferSize.height);
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(goog.webgl.FRAMEBUFFER,
goog.webgl.COLOR_ATTACHMENT0, goog.webgl.TEXTURE_2D, texture, 0);
gl.framebufferRenderbuffer(goog.webgl.FRAMEBUFFER,
goog.webgl.DEPTH_ATTACHMENT, goog.webgl.RENDERBUFFER, renderbuffer);
this.texture_ = texture;
this.renderbuffer_ = renderbuffer;
this.framebuffer_ = framebuffer;
this.framebufferSize_ = framebufferSize;
} else {
gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, this.framebuffer_);
} }
var nTilesX = framebufferDimension / tileSize.width;
var nTilesY = framebufferDimension / tileSize.height;
var framebufferTileBounds = new ol.TileBounds(
tileBounds.minX,
tileBounds.minY,
tileBounds.minX + nTilesX - 1,
tileBounds.minY + nTilesY - 1);
goog.asserts.assert(framebufferTileBounds.contains(tileBounds));
this.bindFramebuffer_(framebufferDimension);
gl.viewport(0, 0, framebufferDimension, framebufferDimension);
gl.clearColor(0, 0, 0, 0); gl.clearColor(0, 0, 0, 0);
gl.clear(goog.webgl.COLOR_BUFFER_BIT); gl.clear(goog.webgl.COLOR_BUFFER_BIT);
@@ -292,13 +319,11 @@ ol.webgl.TileLayerRenderer.prototype.redraw = function() {
if (goog.isNull(this.arrayBuffer_)) { if (goog.isNull(this.arrayBuffer_)) {
var arrayBuffer = gl.createBuffer(); var arrayBuffer = gl.createBuffer();
gl.bindBuffer(goog.webgl.ARRAY_BUFFER, arrayBuffer); gl.bindBuffer(goog.webgl.ARRAY_BUFFER, arrayBuffer);
var textureOffsetX = 0.5 / tileSize.width;
var textureOffsetY = 0.5 / tileSize.height;
gl.bufferData(goog.webgl.ARRAY_BUFFER, new Float32Array([ gl.bufferData(goog.webgl.ARRAY_BUFFER, new Float32Array([
0, 0, 0 + textureOffsetX, 1 + textureOffsetY, -1, -1, 0, 1,
1, 0, 1 + textureOffsetX, 1 + textureOffsetY, 1, -1, 1, 1,
0, 1, 0 + textureOffsetX, 0 + textureOffsetY, -1, 1, 0, 0,
1, 1, 1 + textureOffsetX, 0 + textureOffsetY 1, 1, 1, 0
]), goog.webgl.STATIC_DRAW); ]), goog.webgl.STATIC_DRAW);
this.arrayBuffer_ = arrayBuffer; this.arrayBuffer_ = arrayBuffer;
} else { } else {
@@ -319,16 +344,19 @@ ol.webgl.TileLayerRenderer.prototype.redraw = function() {
} else if (tile.isLoaded()) { } else if (tile.isLoaded()) {
var uMatrix = goog.vec.Mat4.createFloat32Identity(); var uMatrix = goog.vec.Mat4.createFloat32Identity();
goog.vec.Mat4.translate(uMatrix, goog.vec.Mat4.translate(uMatrix,
2 * (tileCoord.x - tileBounds.minX) / tileBoundsSize.width - 1, 0.5 / tileSize.width,
2 * (tileCoord.y - tileBounds.minY) / tileBoundsSize.height - 1, 0.5 / tileSize.height,
0);
goog.vec.Mat4.translate(uMatrix,
2 * (tileCoord.x - framebufferTileBounds.minX + 0.5) / nTilesX - 1,
2 * (tileCoord.y - framebufferTileBounds.minY + 0.5) / nTilesY - 1,
0); 0);
goog.vec.Mat4.scale(uMatrix, goog.vec.Mat4.scale(uMatrix,
2 / tileBoundsSize.width, 1 / nTilesX,
2 / tileBoundsSize.height, 1 / nTilesY,
1); 1);
gl.uniformMatrix4fv(this.locations_.uMatrix, false, uMatrix); gl.uniformMatrix4fv(this.locations_.uMatrix, false, uMatrix);
gl.bindTexture(goog.webgl.TEXTURE_2D, map.getTileTexture(tile)); gl.bindTexture(goog.webgl.TEXTURE_2D, map.getTileTexture(tile));
gl.activeTexture(goog.webgl.TEXTURE0);
gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4);
} else { } else {
var key = goog.getUid(tile); var key = goog.getUid(tile);
@@ -341,6 +369,20 @@ ol.webgl.TileLayerRenderer.prototype.redraw = function() {
} }
}, this); }, this);
var framebufferTileBoundsExtent =
tileGrid.getTileBoundsExtent(z, framebufferTileBounds);
goog.vec.Mat4.makeIdentity(this.matrix_);
goog.vec.Mat4.translate(this.matrix_,
(mapExtent.minX - framebufferTileBoundsExtent.minX) /
(framebufferTileBoundsExtent.maxX - framebufferTileBoundsExtent.minX),
(mapExtent.minY - framebufferTileBoundsExtent.minY) /
(framebufferTileBoundsExtent.maxY - framebufferTileBoundsExtent.minY),
0);
goog.vec.Mat4.scale(this.matrix_,
mapSize.width / framebufferDimension,
mapSize.height / framebufferDimension,
1);
}; };