Merge branch 'master' of github.com:openlayers/ol3 into vector

This commit is contained in:
ahocevar
2013-01-16 16:34:59 +01:00
73 changed files with 3039 additions and 1842 deletions
+11 -29
View File
@@ -1,6 +1,9 @@
goog.provide('ol.renderer.dom.Layer');
goog.require('ol.Coordinate');
goog.require('ol.FrameState');
goog.require('ol.layer.Layer');
goog.require('ol.layer.LayerState');
goog.require('ol.renderer.Layer');
@@ -13,6 +16,7 @@ goog.require('ol.renderer.Layer');
* @param {!Element} target Target.
*/
ol.renderer.dom.Layer = function(mapRenderer, layer, target) {
goog.base(this, mapRenderer, layer);
/**
@@ -21,27 +25,15 @@ ol.renderer.dom.Layer = function(mapRenderer, layer, target) {
*/
this.target = target;
/**
* Top left corner of the target in map coords.
*
* @type {ol.Coordinate}
* @protected
*/
this.origin = null;
this.handleLayerOpacityChange();
this.handleLayerVisibleChange();
};
goog.inherits(ol.renderer.dom.Layer, ol.renderer.Layer);
/**
* @inheritDoc
* @return {ol.renderer.Map} Map renderer.
* @return {!Element} Target.
*/
ol.renderer.dom.Layer.prototype.getMapRenderer = function() {
return /** @type {ol.renderer.dom.Map} */ goog.base(this, 'getMapRenderer');
ol.renderer.dom.Layer.prototype.getTarget = function() {
return this.target;
};
@@ -57,7 +49,7 @@ ol.renderer.dom.Layer.prototype.handleLayerLoad = function() {
* @inheritDoc
*/
ol.renderer.dom.Layer.prototype.handleLayerOpacityChange = function() {
goog.style.setOpacity(this.target, this.getLayer().getOpacity());
this.getMap().render();
};
@@ -65,22 +57,12 @@ ol.renderer.dom.Layer.prototype.handleLayerOpacityChange = function() {
* @inheritDoc
*/
ol.renderer.dom.Layer.prototype.handleLayerVisibleChange = function() {
goog.style.showElement(this.target, this.getLayer().getVisible());
this.getMap().render();
};
/**
* Render.
* @param {number} time Time.
* @param {ol.FrameState} frameState Frame state.
* @param {ol.layer.LayerState} layerState Layer state.
*/
ol.renderer.dom.Layer.prototype.renderFrame = goog.abstractMethod;
/**
* Set the location of the top left corner of the target.
*
* @param {ol.Coordinate} origin Origin.
*/
ol.renderer.dom.Layer.prototype.setOrigin = function(origin) {
this.origin = origin;
};
+30 -204
View File
@@ -5,8 +5,9 @@ goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.functions');
goog.require('goog.style');
goog.require('ol.Coordinate');
goog.require('ol.FrameState');
goog.require('ol.layer.TileLayer');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.dom.TileLayer');
@@ -37,92 +38,32 @@ ol.renderer.dom.Map = function(container, map) {
goog.dom.insertChildAt(container, this.layersPane_, 0);
/**
* @type {Object}
* @private
* @type {boolean}
*/
this.layerPanes_ = {};
this.renderedVisible_ = true;
/**
* @type {ol.Coordinate}
* @private
*/
this.renderedCenter_ = null;
/**
* @type {number | undefined}
* @private
*/
this.renderedResolution_ = undefined;
/**
* @type {ol.Size}
* @private
*/
this.renderedSize_ = null;
/**
* @type {number | undefined}
* @private
*/
this.renderedRotation_ = undefined;
/**
* The origin (top left) of the layers pane in map coordinates.
*
* @type {ol.Coordinate}
* @private
*/
this.layersPaneOrigin_ = null;
};
goog.inherits(ol.renderer.dom.Map, ol.renderer.Map);
/**
* Apply the given transform to the layers pane.
* @param {number} dx Translation along the x-axis.
* @param {number} dy Translation along the y-axis.
* @param {number} rotation Rotation angle.
* @private
*/
ol.renderer.dom.Map.prototype.applyTransform_ = function(dx, dy, rotation) {
var transform =
'translate(' + Math.round(dx) + 'px, ' + Math.round(dy) + 'px) ' +
'rotate(' + rotation.toFixed(6) + 'rad) ' +
'scale3d(1, 1, 1)';
var style = this.layersPane_.style;
style.WebkitTransform = transform;
style.MozTransform = transform;
style.OTransform = transform;
style.msTransform = transform;
style.transform = transform;
};
/**
* @inheritDoc
*/
ol.renderer.dom.Map.prototype.canRotate = goog.functions.TRUE;
ol.renderer.dom.Map.prototype.addLayer = function(layer) {
goog.base(this, 'addLayer', layer);
this.getMap().render();
};
/**
* @inheritDoc
*/
ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) {
if (layer instanceof ol.layer.TileLayer) {
var layerPane = goog.dom.createElement(goog.dom.TagName.DIV);
layerPane.className = 'ol-layer';
layerPane.style.position = 'absolute';
goog.dom.appendChild(this.layersPane_, layerPane);
var layerRenderer = new ol.renderer.dom.TileLayer(this, layer, layerPane);
this.layerPanes_[goog.getUid(layerRenderer)] = layerPane;
var layerRenderer = new ol.renderer.dom.TileLayer(this, layer);
goog.dom.appendChild(this.layersPane_, layerRenderer.getTarget());
return layerRenderer;
} else {
goog.asserts.assert(false);
return null;
@@ -133,8 +74,8 @@ ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) {
/**
* @inheritDoc
*/
ol.renderer.dom.Map.prototype.handleCenterChanged = function() {
goog.base(this, 'handleCenterChanged');
ol.renderer.dom.Map.prototype.removeLayer = function(layer) {
goog.base(this, 'removeLayer', layer);
this.getMap().render();
};
@@ -142,145 +83,30 @@ ol.renderer.dom.Map.prototype.handleCenterChanged = function() {
/**
* @inheritDoc
*/
ol.renderer.dom.Map.prototype.handleResolutionChanged = function() {
goog.base(this, 'handleResolutionChanged');
this.getMap().render();
};
ol.renderer.dom.Map.prototype.renderFrame = function(frameState) {
/**
* @inheritDoc
*/
ol.renderer.dom.Map.prototype.handleRotationChanged = function() {
goog.base(this, 'handleRotationChanged');
this.getMap().render();
};
/**
* @inheritDoc
*/
ol.renderer.dom.Map.prototype.handleSizeChanged = function() {
goog.base(this, 'handleSizeChanged');
this.getMap().render();
};
/**
* Render the map. Sets up the layers pane on first render and adjusts its
* position as needed on subsequent calls.
* @inheritDoc
*/
ol.renderer.dom.Map.prototype.renderFrame = function(time) {
var map = this.getMap();
if (!map.isDef()) {
if (goog.isNull(frameState)) {
if (this.renderedVisible_) {
goog.style.showElement(this.layersPane_, false);
this.renderedVisible_ = false;
}
return;
}
var mapCenter = map.getCenter();
var mapSize = map.getSize();
var mapResolution = map.getResolution();
var mapRotation = map.getRotation();
goog.asserts.assert(goog.isDefAndNotNull(mapCenter));
goog.asserts.assert(goog.isDef(mapResolution));
goog.asserts.assert(goog.isDef(mapRotation));
goog.asserts.assert(goog.isDefAndNotNull(mapSize));
if (goog.isNull(this.renderedCenter_)) {
// first rendering
goog.asserts.assert(!goog.isDef(this.renderedResolution_));
goog.asserts.assert(!goog.isDef(this.renderedRotation_));
goog.asserts.assert(goog.isNull(this.renderedSize_));
this.resetLayersPane_();
} else {
goog.asserts.assert(goog.isDef(this.renderedResolution_));
goog.asserts.assert(!goog.isNull(this.renderedSize_));
if (mapResolution !== this.renderedResolution_ ||
!mapSize.equals(this.renderedSize_)) {
// resolution or size changed, adjust layers pane
this.resetLayersPane_();
} else if (!mapCenter.equals(this.renderedCenter_) ||
mapRotation !== this.renderedRotation_) {
// same resolution and size, new center or rotation
this.transformLayersPane_();
goog.array.forEach(frameState.layersArray, function(layer) {
var layerState = frameState.layerStates[goog.getUid(layer)];
if (!layerState.ready) {
return;
}
var layerRenderer = this.getLayerRenderer(layer);
layerRenderer.renderFrame(frameState, layerState);
}, this);
if (!this.renderedVisible_) {
goog.style.showElement(this.layersPane_, true);
this.renderedVisible_ = true;
}
this.renderedCenter_ = mapCenter;
this.renderedResolution_ = mapResolution;
this.renderedRotation_ = mapRotation;
this.renderedSize_ = mapSize;
var requestRenderFrame = false;
this.forEachReadyVisibleLayer(function(layer, layerRenderer) {
if (layerRenderer.renderFrame(time)) {
requestRenderFrame = true;
}
});
if (requestRenderFrame) {
map.requestRenderFrame();
}
this.calculateMatrices2D(frameState);
};
/**
* Reset the layers pane to its initial position.
* @private
*/
ol.renderer.dom.Map.prototype.resetLayersPane_ = function() {
var map = this.map;
var mapSize = map.getSize();
var halfWidth = mapSize.width / 2;
var halfHeight = mapSize.height / 2;
var center = map.getCenter();
var resolution = map.getResolution();
var origin = new ol.Coordinate(
center.x - resolution * halfWidth,
center.y + resolution * halfHeight);
this.layersPaneOrigin_ = origin;
this.setTransformOrigin_(halfWidth, halfHeight);
this.applyTransform_(0, 0, map.getRotation());
goog.object.forEach(this.layerRenderers, function(layerRenderer) {
layerRenderer.setOrigin(origin);
});
};
/**
* Set the transform-origin CSS property of the layers pane.
* @param {number} x The x-axis origin.
* @param {number} y The y-axis origin.
* @private
*/
ol.renderer.dom.Map.prototype.setTransformOrigin_ = function(x, y) {
var origin = Math.round(x) + 'px ' + Math.round(y) + 'px';
var style = this.layersPane_.style;
style.WebkitTransformOrigin = origin;
style.MozTransformOrigin = origin;
style.OTransformOrigin = origin;
style.msTransformOrigin = origin;
style.transformOrigin = origin;
};
/**
* Apply the appropriate transform to the layers pane.
* @private
*/
ol.renderer.dom.Map.prototype.transformLayersPane_ = function() {
var map = this.map;
var resolution = map.getResolution();
var center = map.getCenter();
var size = map.getSize();
var origin = this.layersPaneOrigin_;
var ox = (center.x - origin.x) / resolution;
var oy = (origin.y - center.y) / resolution;
this.setTransformOrigin_(ox, oy);
var dx = ox - (size.width / 2);
var dy = oy - (size.height / 2);
this.applyTransform_(-dx, -dy, map.getRotation());
};
+324 -163
View File
@@ -1,13 +1,23 @@
// FIXME probably need to reset TileLayerZ if offsets get too large
// FIXME when zooming out, preserve higher Z divs to avoid white flash
goog.provide('ol.renderer.dom.TileLayer');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.math.Vec2');
goog.require('goog.style');
goog.require('goog.vec.Mat4');
goog.require('ol.Coordinate');
goog.require('ol.Extent');
goog.require('ol.Size');
goog.require('ol.TileCoord');
goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.ViewHint');
goog.require('ol.dom');
goog.require('ol.renderer.dom.Layer');
goog.require('ol.tilegrid.TileGrid');
@@ -16,212 +26,363 @@ goog.require('ol.renderer.dom.Layer');
* @extends {ol.renderer.dom.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.TileLayer} tileLayer Tile layer.
* @param {!Element} target Target.
*/
ol.renderer.dom.TileLayer = function(mapRenderer, tileLayer, target) {
ol.renderer.dom.TileLayer = function(mapRenderer, tileLayer) {
var target = goog.dom.createElement(goog.dom.TagName.DIV);
target.className = 'ol-layer';
target.style.position = 'absolute';
goog.base(this, mapRenderer, tileLayer, target);
/**
* @type {Object}
* @private
* @type {boolean}
*/
this.renderedTiles_ = {};
this.renderedVisible_ = true;
/**
* @type {number|undefined}
* @private
* @type {number}
*/
this.renderedMapResolution_ = undefined;
this.renderedOpacity_ = 1;
/**
* @private
* @type {Object.<number, ol.renderer.dom.TileLayerZ_>}
*/
this.tileLayerZs_ = {};
};
goog.inherits(ol.renderer.dom.TileLayer, ol.renderer.dom.Layer);
/**
* @return {ol.layer.TileLayer} Tile layer.
*/
ol.renderer.dom.TileLayer.prototype.getTileLayer = function() {
return /** @type {ol.layer.TileLayer} */ (this.getLayer());
};
/**
* @inheritDoc
* @return {ol.layer.TileLayer} Layer.
*/
ol.renderer.dom.TileLayer.prototype.getLayer = function() {
return /** @type {ol.layer.TileLayer} */ goog.base(this, 'getLayer');
};
ol.renderer.dom.TileLayer.prototype.renderFrame =
function(frameState, layerState) {
/**
* Get the pixel offset between the tile origin and the container origin.
* @private
* @param {number} z Z.
* @param {number} resolution Resolution.
* @return {ol.Coordinate} Offset.
*/
ol.renderer.dom.TileLayer.prototype.getTileOffset_ = function(z, resolution) {
var tileLayer = this.getLayer();
var tileSource = tileLayer.getTileSource();
var tileGrid = tileSource.getTileGrid();
var tileOrigin = tileGrid.getOrigin(z);
var offset = new ol.Coordinate(
Math.round((this.origin.x - tileOrigin.x) / resolution),
Math.round((tileOrigin.y - this.origin.y) / resolution));
return offset;
};
/**
* Get rid of all tiles that weren't drawn in the most recent rendering.
* @param {Object.<number, Object.<string, ol.Tile>>} tilesDrawnByZ Tiles just
* rendered.
* @private
*/
ol.renderer.dom.TileLayer.prototype.removeExtraTiles_ =
function(tilesDrawnByZ) {
var key, tileCoord, tilesDrawn, tile;
for (key in this.renderedTiles_) {
tileCoord = ol.TileCoord.createFromString(key);
tilesDrawn = tilesDrawnByZ[tileCoord.z];
if (!(tilesDrawn && key in tilesDrawn)) {
tile = this.renderedTiles_[key];
delete this.renderedTiles_[key];
goog.dom.removeNode(tile.getImage(this));
if (!layerState.visible) {
if (this.renderedVisible_) {
goog.style.showElement(this.target, false);
this.renderedVisible_ = false;
}
}
};
/**
* @inheritDoc
*/
ol.renderer.dom.TileLayer.prototype.renderFrame = function(time) {
var map = this.getMap();
if (!map.isDef()) {
return;
}
var mapExtent = /** @type {!ol.Extent} */ map.getRotatedExtent();
var mapResolution = /** @type {number} */ map.getResolution();
var resolutionChanged = (mapResolution !== this.renderedMapResolution_);
var tileLayer = this.getLayer();
var view2DState = frameState.view2DState;
var tileLayer = this.getTileLayer();
var tileSource = tileLayer.getTileSource();
var tileGrid = tileSource.getTileGrid();
var z = tileGrid.getZForResolution(view2DState.resolution);
var tileResolution = tileGrid.getResolution(z);
var tileRange = tileGrid.getTileRangeForExtentAndResolution(
frameState.extent, tileResolution);
// z represents the "best" resolution
var z = tileGrid.getZForResolution(mapResolution);
/**
* @type {Object.<number, Object.<string, ol.Tile>>}
*/
/** @type {Object.<number, Object.<string, ol.Tile>>} */
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
var tileRange =
tileGrid.getTileRangeForExtentAndResolution(mapExtent, mapResolution);
var findInterimTiles = function(z, tileRange) {
// FIXME this could be more efficient about filling partial holes
var fullyCovered = true;
var tile, tileCoord, tileCoordKey, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
tileCoordKey = tileCoord.toString();
if (tilesToDrawByZ[z] && tilesToDrawByZ[z][tileCoordKey]) {
return;
}
tile = tileSource.getTile(tileCoord);
if (!goog.isNull(tile) && tile.getState() == ol.TileState.LOADED) {
if (!tilesToDrawByZ[z]) {
tilesToDrawByZ[z] = {};
}
tilesToDrawByZ[z][tileCoordKey] = tile;
} else {
fullyCovered = false;
}
}
}
return fullyCovered;
};
var allTilesLoaded = true;
var tile, tileCenter, tileCoord, tileState, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
tile = tileSource.getTile(tileCoord);
if (goog.isNull(tile)) {
continue;
}
tileState = tile.getState();
if (tileState == ol.TileState.IDLE) {
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
frameState.tileQueue.enqueue(tile, tileCenter, tileResolution);
} else if (tileState == ol.TileState.LOADED) {
tilesToDrawByZ[z][tileCoord.toString()] = tile;
continue;
} else if (tileState == ol.TileState.ERROR) {
continue;
}
allTilesLoaded = false;
tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles);
// first pass through the tile range to determine all the tiles needed
tileRange.forEachTileCoord(z, function(tileCoord) {
var tile = tileSource.getTile(tileCoord);
if (goog.isNull(tile)) {
// we're outside the source's extent, continue
return;
}
var key = tile.tileCoord.toString();
var state = tile.getState();
if (state == ol.TileState.IDLE) {
tile.load();
} else if (state == ol.TileState.LOADED) {
tilesToDrawByZ[z][key] = tile;
return;
}
allTilesLoaded = false;
/**
* Look for already loaded tiles at alternate z that can serve as
* placeholders until tiles at the current z have loaded.
*
* TODO: make this more efficent for filling partial holes
*/
tileGrid.forEachTileCoordParentTileRange(
tileCoord,
function(altZ, altTileRange) {
var fullyCovered = true;
altTileRange.forEachTileCoord(altZ, function(altTileCoord) {
var tileKey = altTileCoord.toString();
if (tilesToDrawByZ[altZ] && tilesToDrawByZ[altZ][tileKey]) {
return;
}
var altTile = tileSource.getTile(altTileCoord);
if (!goog.isNull(altTile) &&
altTile.getState() == ol.TileState.LOADED) {
if (!(altZ in tilesToDrawByZ)) {
tilesToDrawByZ[altZ] = {};
}
tilesToDrawByZ[altZ][tileKey] = altTile;
} else {
fullyCovered = false;
}
});
return fullyCovered;
});
}, this);
}
/** @type {Array.<number>} */
var zs = goog.array.map(goog.object.getKeys(tilesToDrawByZ), Number);
goog.array.sort(zs);
var fragment = document.createDocumentFragment();
var altFragment = document.createDocumentFragment();
var newTiles = false;
var newAltTiles = false;
for (var i = 0, ii = zs.length; i < ii; ++i) {
var tileZ = zs[i];
var tilesToDraw = tilesToDrawByZ[tileZ];
var tileOffset = this.getTileOffset_(tileZ, mapResolution);
for (var key in tilesToDraw) {
var tile = tilesToDraw[key];
var tileCoord = tile.tileCoord;
var pixelBounds = tileGrid.getPixelBoundsForTileCoordAndResolution(
tileCoord, mapResolution);
var img = tile.getImage(this);
var style = img.style;
var append = !(key in this.renderedTiles_);
if (append || resolutionChanged) {
style.left = (pixelBounds.minX - tileOffset.x) + 'px';
style.top = (-pixelBounds.maxY - tileOffset.y) + 'px';
style.width = pixelBounds.getWidth() + 'px';
style.height = pixelBounds.getHeight() + 'px';
}
if (append) {
this.renderedTiles_[key] = tile;
style.position = 'absolute';
if (tileZ === z) {
goog.dom.appendChild(fragment, img);
newTiles = true;
} else {
goog.dom.appendChild(altFragment, img);
newAltTiles = true;
/** @type {Object.<number, boolean>} */
var newTileLayerZKeys = {};
var tileSize = tileGrid.getTileSize();
var iz, tileCoordKey, tileCoordOrigin, tileLayerZ, tileLayerZKey, tilesToDraw;
for (iz = 0; iz < zs.length; ++iz) {
tileLayerZKey = zs[iz];
if (tileLayerZKey in this.tileLayerZs_) {
tileLayerZ = this.tileLayerZs_[tileLayerZKey];
} else {
tileCoordOrigin =
tileGrid.getTileCoordForCoordAndZ(view2DState.center, tileLayerZKey);
tileLayerZ = new ol.renderer.dom.TileLayerZ_(tileGrid, tileCoordOrigin);
newTileLayerZKeys[tileLayerZKey] = true;
this.tileLayerZs_[tileLayerZKey] = tileLayerZ;
}
tilesToDraw = tilesToDrawByZ[tileLayerZKey];
for (tileCoordKey in tilesToDraw) {
tileLayerZ.addTile(tilesToDraw[tileCoordKey]);
}
tileLayerZ.finalizeAddTiles();
}
/** @type {Array.<number>} */
var tileLayerZKeys =
goog.array.map(goog.object.getKeys(this.tileLayerZs_), Number);
goog.array.sort(tileLayerZKeys);
var i, j, origin, resolution;
var transform = goog.vec.Mat4.createNumber();
for (i = 0; i < tileLayerZKeys.length; ++i) {
tileLayerZKey = tileLayerZKeys[i];
tileLayerZ = this.tileLayerZs_[tileLayerZKey];
if (!(tileLayerZKey in tilesToDrawByZ)) {
goog.dom.removeNode(tileLayerZ.target);
delete this.tileLayerZs_[tileLayerZKey];
continue;
}
resolution = tileLayerZ.getResolution();
origin = tileLayerZ.getOrigin();
goog.vec.Mat4.makeIdentity(transform);
goog.vec.Mat4.translate(
transform, frameState.size.width / 2, frameState.size.height / 2, 0);
goog.vec.Mat4.rotateZ(transform, view2DState.rotation);
goog.vec.Mat4.scale(transform, resolution / view2DState.resolution,
resolution / view2DState.resolution, 1);
goog.vec.Mat4.translate(
transform,
(origin.x - view2DState.center.x) / resolution,
(view2DState.center.y - origin.y) / resolution,
0);
tileLayerZ.setTransform(transform);
if (tileLayerZKey in newTileLayerZKeys) {
for (j = tileLayerZKey - 1; j >= 0; --j) {
if (j in this.tileLayerZs_) {
goog.dom.insertSiblingAfter(
tileLayerZ.target, this.tileLayerZs_[j].target);
break;
}
}
}
}
if (newAltTiles) {
var child = this.target.firstChild;
if (child) {
goog.dom.insertSiblingBefore(altFragment, child);
if (j < 0) {
goog.dom.insertChildAt(this.target, tileLayerZ.target, 0);
}
} else {
goog.dom.appendChild(this.target, altFragment);
if (!frameState.viewHints[ol.ViewHint.ANIMATING] &&
!frameState.viewHints[ol.ViewHint.PANNING]) {
tileLayerZ.removeTilesOutsideExtent(frameState.extent);
}
}
}
if (newTiles) {
goog.dom.appendChild(this.target, fragment);
if (layerState.opacity != this.renderedOpacity_) {
goog.style.setOpacity(this.target, layerState.opacity);
this.renderedOpacity_ = layerState.opacity;
}
this.renderedMapResolution_ = mapResolution;
if (layerState.visible && !this.renderedVisible_) {
goog.style.showElement(this.target, true);
this.renderedVisible_ = true;
}
this.removeExtraTiles_(tilesToDrawByZ);
if (!allTilesLoaded) {
frameState.animate = true;
}
return !allTilesLoaded;
};
/**
* @constructor
* @private
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
* @param {ol.TileCoord} tileCoordOrigin Tile coord origin.
*/
ol.renderer.dom.TileLayerZ_ = function(tileGrid, tileCoordOrigin) {
/**
* @type {!Element}
*/
this.target = goog.dom.createElement(goog.dom.TagName.DIV);
this.target.style.position = 'absolute';
/**
* @private
* @type {ol.tilegrid.TileGrid}
*/
this.tileGrid_ = tileGrid;
/**
* @private
* @type {ol.TileCoord}
*/
this.tileCoordOrigin_ = tileCoordOrigin;
/**
* @private
* @type {ol.Coordinate}
*/
this.origin_ = tileGrid.getTileCoordExtent(tileCoordOrigin).getTopLeft();
/**
* @private
* @type {number}
*/
this.resolution_ = tileGrid.getResolution(tileCoordOrigin.z);
/**
* @private
* @type {Object.<string, ol.Tile>}
*/
this.tiles_ = {};
/**
* @private
* @type {DocumentFragment}
*/
this.documentFragment_ = null;
/**
* @private
* @type {goog.vec.Mat4.AnyType}
*/
this.transform_ = goog.vec.Mat4.createNumberIdentity();
};
/**
* @param {ol.Tile} tile Tile.
*/
ol.renderer.dom.TileLayerZ_.prototype.addTile = function(tile) {
var tileCoord = tile.tileCoord;
goog.asserts.assert(tileCoord.z == this.tileCoordOrigin_.z);
var tileCoordKey = tileCoord.toString();
if (tileCoordKey in this.tiles_) {
return;
}
var tileSize = this.tileGrid_.getTileSize();
var image = tile.getImage(this);
var style = image.style;
style.position = 'absolute';
style.left =
((tileCoord.x - this.tileCoordOrigin_.x) * tileSize.width) + 'px';
style.top =
((this.tileCoordOrigin_.y - tileCoord.y) * tileSize.height) + 'px';
if (goog.isNull(this.documentFragment_)) {
this.documentFragment_ = document.createDocumentFragment();
}
goog.dom.appendChild(this.documentFragment_, image);
this.tiles_[tileCoordKey] = tile;
};
/**
* FIXME empty description for jsdoc
*/
ol.renderer.dom.TileLayerZ_.prototype.finalizeAddTiles = function() {
if (!goog.isNull(this.documentFragment_)) {
goog.dom.appendChild(this.target, this.documentFragment_);
this.documentFragment_ = null;
}
};
/**
* @return {ol.Coordinate} Origin.
*/
ol.renderer.dom.TileLayerZ_.prototype.getOrigin = function() {
return this.origin_;
};
/**
* @return {number} Resolution.
*/
ol.renderer.dom.TileLayerZ_.prototype.getResolution = function() {
return this.resolution_;
};
/**
* @param {ol.Extent} extent Extent.
*/
ol.renderer.dom.TileLayerZ_.prototype.removeTilesOutsideExtent =
function(extent) {
var tileRange =
this.tileGrid_.getTileRangeForExtentAndZ(extent, this.tileCoordOrigin_.z);
var tilesToRemove = [];
var tile, tileCoordKey;
for (tileCoordKey in this.tiles_) {
tile = this.tiles_[tileCoordKey];
if (!tileRange.contains(tile.tileCoord)) {
tilesToRemove.push(tile);
}
}
var i;
for (i = 0; i < tilesToRemove.length; ++i) {
tile = tilesToRemove[i];
tileCoordKey = tile.tileCoord.toString();
goog.dom.removeNode(tile.getImage(this));
delete this.tiles_[tileCoordKey];
}
};
/**
* @param {goog.vec.Mat4.AnyType} transform Transform.
*/
ol.renderer.dom.TileLayerZ_.prototype.setTransform = function(transform) {
if (!goog.vec.Mat4.equals(transform, this.transform_)) {
ol.dom.transformElement2D(this.target, transform, 6);
goog.vec.Mat4.setFromArray(this.transform_, transform);
}
};
+68 -139
View File
@@ -1,11 +1,15 @@
goog.provide('ol.renderer.Map');
goog.require('goog.Disposable');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.functions');
goog.require('goog.fx.anim');
goog.require('goog.fx.anim.Animated');
goog.require('goog.vec.Mat4');
goog.require('ol.FrameState');
goog.require('ol.View2D');
goog.require('ol.View2DProperty');
@@ -43,23 +47,12 @@ ol.renderer.Map = function(container, map) {
*/
this.layersListenerKeys_ = null;
/**
* @private
* @type {goog.vec.Mat4.Number}
*/
this.coordinateToPixelMatrix_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {goog.vec.Mat4.Number}
* @type {?number}
*/
this.pixelToCoordinateMatrix_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {boolean}
*/
this.matricesDirty_ = true;
this.viewPropertyListenerKey_ = null;
/**
* @private
@@ -70,25 +63,17 @@ ol.renderer.Map = function(container, map) {
map, ol.Object.getChangedEventType(ol.MapProperty.BACKGROUND_COLOR),
this.handleBackgroundColorChanged, false, this),
goog.events.listen(
map, ol.Object.getChangedEventType(ol.MapProperty.CENTER),
this.handleCenterChanged, false, this),
goog.events.listen(
map, ol.Object.getChangedEventType(ol.MapProperty.LAYERS),
this.handleLayersChanged, false, this),
goog.events.listen(
map, ol.Object.getChangedEventType(ol.MapProperty.RESOLUTION),
this.handleResolutionChanged, false, this),
goog.events.listen(
map, ol.Object.getChangedEventType(ol.MapProperty.ROTATION),
this.handleRotationChanged, false, this),
goog.events.listen(
map, ol.Object.getChangedEventType(ol.MapProperty.SIZE),
this.handleSizeChanged, false, this)
this.handleSizeChanged, false, this),
goog.events.listen(
map, ol.Object.getChangedEventType(ol.MapProperty.VIEW),
this.handleViewChanged, false, this)
];
};
@@ -106,9 +91,35 @@ ol.renderer.Map.prototype.addLayer = function(layer) {
/**
* @return {boolean} Can rotate.
* @param {ol.FrameState} frameState FrameState.
* @protected
*/
ol.renderer.Map.prototype.canRotate = goog.functions.FALSE;
ol.renderer.Map.prototype.calculateMatrices2D = function(frameState) {
var view2DState = frameState.view2DState;
var coordinateToPixelMatrix = frameState.coordinateToPixelMatrix;
goog.vec.Mat4.makeIdentity(coordinateToPixelMatrix);
goog.vec.Mat4.translate(coordinateToPixelMatrix,
frameState.size.width / 2,
frameState.size.height / 2,
0);
goog.vec.Mat4.scale(coordinateToPixelMatrix,
1 / view2DState.resolution,
-1 / view2DState.resolution,
1);
goog.vec.Mat4.rotateZ(coordinateToPixelMatrix,
-view2DState.rotation);
goog.vec.Mat4.translate(coordinateToPixelMatrix,
-view2DState.center.x,
-view2DState.center.y,
0);
var inverted = goog.vec.Mat4.invert(
coordinateToPixelMatrix, frameState.pixelToCoordinateMatrix);
goog.asserts.assert(inverted);
};
/**
@@ -127,6 +138,9 @@ ol.renderer.Map.prototype.disposeInternal = function() {
goog.dispose(layerRenderer);
});
goog.array.forEach(this.mapListenerKeys_, goog.events.unlistenByKey);
if (!goog.isNull(this.viewPropertyListenerKey_)) {
goog.events.unlistenByKey(this.viewPropertyListenerKey_);
}
if (!goog.isNull(this.layersListenerKeys_)) {
goog.array.forEach(this.layersListenerKeys_, goog.events.unlistenByKey);
}
@@ -134,37 +148,6 @@ ol.renderer.Map.prototype.disposeInternal = function() {
};
/**
* @param {function(this: T, ol.layer.Layer, ol.renderer.Layer, number)} f
* Function.
* @param {T=} opt_obj Object.
* @template T
*/
ol.renderer.Map.prototype.forEachReadyVisibleLayer = function(f, opt_obj) {
var layers = this.map.getLayers();
if (goog.isDef(layers)) {
layers.forEach(function(layer, index) {
if (layer.isReady() && layer.getVisible()) {
var layerRenderer = this.getLayerRenderer(layer);
f.call(opt_obj, layer, layerRenderer, index);
}
}, this);
}
};
/**
* @param {ol.Pixel} pixel Pixel.
* @return {ol.Coordinate} Coordinate.
*/
ol.renderer.Map.prototype.getCoordinateFromPixel = function(pixel) {
this.updateMatrices_();
var vec3 = [pixel.x, pixel.y, 0];
goog.vec.Mat4.multVec3(this.pixelToCoordinateMatrix_, vec3, vec3);
return new ol.Coordinate(vec3[0], vec3[1]);
};
/**
* @param {ol.layer.Layer} layer Layer.
* @protected
@@ -186,38 +169,18 @@ ol.renderer.Map.prototype.getMap = function() {
};
/**
* @param {ol.Coordinate} coordinate Coordinate.
* @return {ol.Pixel} Pixel.
*/
ol.renderer.Map.prototype.getPixelFromCoordinate = function(coordinate) {
this.updateMatrices_();
var vec3 = [coordinate.x, coordinate.y, 0];
goog.vec.Mat4.multVec3(this.coordinateToPixelMatrix_, vec3, vec3);
return new ol.Pixel(vec3[0], vec3[1]);
};
/**
* Handle background color changed.
*/
ol.renderer.Map.prototype.handleBackgroundColorChanged = goog.nullFunction;
/**
* @protected
*/
ol.renderer.Map.prototype.handleCenterChanged = function() {
this.matricesDirty_ = true;
};
/**
* @param {ol.CollectionEvent} collectionEvent Collection event.
* @protected
*/
ol.renderer.Map.prototype.handleLayersAdd = function(collectionEvent) {
var layer = /** @type {ol.layer.Layer} */ collectionEvent.elem;
var layer = /** @type {ol.layer.Layer} */ (collectionEvent.elem);
this.addLayer(layer);
};
@@ -226,10 +189,7 @@ ol.renderer.Map.prototype.handleLayersAdd = function(collectionEvent) {
* @protected
*/
ol.renderer.Map.prototype.handleLayersChanged = function() {
var layerRenderers = goog.object.getValues(this.layerRenderers);
goog.array.forEach(layerRenderers, function(layerRenderer) {
this.removeLayerRenderer(layerRenderer);
}, this);
goog.disposeAll(goog.object.getValues(this.layerRenderers));
this.layerRenderers = {};
if (!goog.isNull(this.layersListenerKeys_)) {
goog.array.forEach(this.layersListenerKeys_, goog.events.unlistenByKey);
@@ -253,7 +213,7 @@ ol.renderer.Map.prototype.handleLayersChanged = function() {
* @protected
*/
ol.renderer.Map.prototype.handleLayersRemove = function(collectionEvent) {
var layer = /** @type {ol.layer.Layer} */ collectionEvent.elem;
var layer = /** @type {ol.layer.Layer} */ (collectionEvent.elem);
this.removeLayer(layer);
};
@@ -261,16 +221,8 @@ ol.renderer.Map.prototype.handleLayersRemove = function(collectionEvent) {
/**
* @protected
*/
ol.renderer.Map.prototype.handleResolutionChanged = function() {
this.matricesDirty_ = true;
};
/**
* @protected
*/
ol.renderer.Map.prototype.handleRotationChanged = function() {
this.matricesDirty_ = true;
ol.renderer.Map.prototype.handleViewPropertyChanged = function() {
this.getMap().render();
};
@@ -278,7 +230,25 @@ ol.renderer.Map.prototype.handleRotationChanged = function() {
* @protected
*/
ol.renderer.Map.prototype.handleSizeChanged = function() {
this.matricesDirty_ = true;
this.getMap().render();
};
/**
* @protected
*/
ol.renderer.Map.prototype.handleViewChanged = function() {
if (!goog.isNull(this.viewPropertyListenerKey_)) {
goog.events.unlistenByKey(this.viewPropertyListenerKey_);
this.viewPropertyListenerKey_ = null;
}
var view = this.getMap().getView();
if (goog.isDefAndNotNull(view)) {
this.viewPropertyListenerKey_ = goog.events.listen(
view, ol.ObjectEventType.CHANGED,
this.handleViewPropertyChanged, false, this);
}
this.getMap().render();
};
@@ -310,9 +280,9 @@ ol.renderer.Map.prototype.removeLayerRenderer = function(layer) {
/**
* Render.
* @param {number} time Time.
* @param {?ol.FrameState} frameState Frame state.
*/
ol.renderer.Map.prototype.renderFrame = goog.functions.FALSE;
ol.renderer.Map.prototype.renderFrame = goog.nullFunction;
/**
@@ -325,44 +295,3 @@ ol.renderer.Map.prototype.setLayerRenderer = function(layer, layerRenderer) {
goog.asserts.assert(!(key in this.layerRenderers));
this.layerRenderers[key] = layerRenderer;
};
/**
* @private
*/
ol.renderer.Map.prototype.updateMatrices_ = function() {
if (this.matricesDirty_) {
var map = this.map;
var center = /** @type {!ol.Coordinate} */ map.getCenter();
var resolution = /** @type {number} */ map.getResolution();
var rotation = map.getRotation();
var size = /** @type {!ol.Size} */ map.getSize();
goog.vec.Mat4.makeIdentity(this.coordinateToPixelMatrix_);
goog.vec.Mat4.translate(this.coordinateToPixelMatrix_,
size.width / 2,
size.height / 2,
0);
goog.vec.Mat4.scale(this.coordinateToPixelMatrix_,
1 / resolution,
-1 / resolution,
1);
if (this.canRotate() && goog.isDef(rotation)) {
goog.vec.Mat4.rotateZ(this.coordinateToPixelMatrix_, -rotation);
}
goog.vec.Mat4.translate(this.coordinateToPixelMatrix_,
-center.x,
-center.y,
0);
var inverted = goog.vec.Mat4.invert(
this.coordinateToPixelMatrix_, this.pixelToCoordinateMatrix_);
goog.asserts.assert(inverted);
this.matricesDirty_ = false;
}
};
+93 -8
View File
@@ -1,8 +1,13 @@
// FIXME move colorMatrix_ elsewhere?
goog.provide('ol.renderer.webgl.Layer');
goog.require('goog.vec.Mat4');
goog.require('ol.FrameState');
goog.require('ol.layer.Layer');
goog.require('ol.layer.LayerState');
goog.require('ol.renderer.Layer');
goog.require('ol.vec.Mat4');
@@ -13,7 +18,50 @@ goog.require('ol.renderer.Layer');
* @param {ol.layer.Layer} layer Layer.
*/
ol.renderer.webgl.Layer = function(mapRenderer, layer) {
goog.base(this, mapRenderer, layer);
/**
* @private
* @type {!goog.vec.Mat4.Float32}
*/
this.brightnessMatrix_ = goog.vec.Mat4.createFloat32();
/**
* @private
* @type {!goog.vec.Mat4.Float32}
*/
this.contrastMatrix_ = goog.vec.Mat4.createFloat32();
/**
* @private
* @type {!goog.vec.Mat4.Float32}
*/
this.hueMatrix_ = goog.vec.Mat4.createFloat32();
/**
* @private
* @type {!goog.vec.Mat4.Float32}
*/
this.saturationMatrix_ = goog.vec.Mat4.createFloat32();
/**
* @private
* @type {!goog.vec.Mat4.Float32}
*/
this.colorMatrix_ = goog.vec.Mat4.createFloat32();
/**
* @private
* @type {boolean}
*/
this.colorMatrixDirty_ = true;
this.handleLayerBrightnessChange();
this.handleLayerContrastChange();
this.handleLayerHueChange();
this.handleLayerSaturationChange();
};
goog.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer);
@@ -27,17 +75,28 @@ ol.renderer.webgl.Layer.prototype.dispatchChangeEvent = function() {
/**
* @inheritDoc
* @return {ol.renderer.Map} MapRenderer.
* @return {!goog.vec.Mat4.Float32} Color matrix.
*/
ol.renderer.webgl.Layer.prototype.getMapRenderer = function() {
return /** @type {ol.renderer.webgl.Map} */ goog.base(
this, 'getMapRenderer');
ol.renderer.webgl.Layer.prototype.getColorMatrix = function() {
if (this.colorMatrixDirty_) {
this.updateColorMatrix_();
}
return this.colorMatrix_;
};
/**
* @return {goog.vec.Mat4.AnyType} Matrix.
* @inheritDoc
* @return {ol.renderer.Map} MapRenderer.
*/
ol.renderer.webgl.Layer.prototype.getMapRenderer = function() {
return /** @type {ol.renderer.webgl.Map} */ (goog.base(
this, 'getMapRenderer'));
};
/**
* @return {!goog.vec.Mat4.Number} Matrix.
*/
ol.renderer.webgl.Layer.prototype.getMatrix = goog.abstractMethod;
@@ -52,6 +111,9 @@ ol.renderer.webgl.Layer.prototype.getTexture = goog.abstractMethod;
* @inheritDoc
*/
ol.renderer.webgl.Layer.prototype.handleLayerBrightnessChange = function() {
var value = this.getLayer().getBrightness();
ol.vec.Mat4.makeBrightness(this.brightnessMatrix_, value);
this.colorMatrixDirty_ = true;
this.dispatchChangeEvent();
};
@@ -60,6 +122,9 @@ ol.renderer.webgl.Layer.prototype.handleLayerBrightnessChange = function() {
* @inheritDoc
*/
ol.renderer.webgl.Layer.prototype.handleLayerContrastChange = function() {
var value = this.getLayer().getContrast();
ol.vec.Mat4.makeContrast(this.contrastMatrix_, value);
this.colorMatrixDirty_ = true;
this.dispatchChangeEvent();
};
@@ -68,6 +133,9 @@ ol.renderer.webgl.Layer.prototype.handleLayerContrastChange = function() {
* @inheritDoc
*/
ol.renderer.webgl.Layer.prototype.handleLayerHueChange = function() {
var value = this.getLayer().getHue();
ol.vec.Mat4.makeHue(this.hueMatrix_, value);
this.colorMatrixDirty_ = true;
this.dispatchChangeEvent();
};
@@ -92,6 +160,9 @@ ol.renderer.webgl.Layer.prototype.handleLayerOpacityChange = function() {
* @inheritDoc
*/
ol.renderer.webgl.Layer.prototype.handleLayerSaturationChange = function() {
var saturation = this.getLayer().getSaturation();
ol.vec.Mat4.makeSaturation(this.saturationMatrix_, saturation);
this.colorMatrixDirty_ = true;
this.dispatchChangeEvent();
};
@@ -112,7 +183,21 @@ ol.renderer.webgl.Layer.prototype.handleWebGLContextLost = goog.nullFunction;
/**
* Render.
* @param {number} time Time.
* @return {boolean} Request render frame.
* @param {ol.FrameState} frameState Frame state.
* @param {ol.layer.LayerState} layerState Layer state.
*/
ol.renderer.webgl.Layer.prototype.renderFrame = goog.abstractMethod;
/**
* @private
*/
ol.renderer.webgl.Layer.prototype.updateColorMatrix_ = function() {
var colorMatrix = this.colorMatrix_;
goog.vec.Mat4.makeIdentity(colorMatrix);
goog.vec.Mat4.multMat(colorMatrix, this.contrastMatrix_, colorMatrix);
goog.vec.Mat4.multMat(colorMatrix, this.brightnessMatrix_, colorMatrix);
goog.vec.Mat4.multMat(colorMatrix, this.saturationMatrix_, colorMatrix);
goog.vec.Mat4.multMat(colorMatrix, this.hueMatrix_, colorMatrix);
this.colorMatrixDirty_ = false;
};
+50 -194
View File
@@ -1,7 +1,5 @@
// FIXME clear textureCache
// FIXME defer texture loads until after render when animating
// FIXME generational tile texture garbage collector newFrame/get
// FIXME defer cleanup until post-render
// FIXME check against gl.getParameter(webgl.MAX_TEXTURE_SIZE)
goog.provide('ol.renderer.webgl.Map');
@@ -14,10 +12,9 @@ goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventType');
goog.require('goog.functions');
goog.require('goog.style');
goog.require('goog.vec.Mat4');
goog.require('goog.webgl');
goog.require('ol.Tile');
goog.require('ol.layer.Layer');
goog.require('ol.layer.TileLayer');
goog.require('ol.renderer.webgl.FragmentShader');
@@ -119,6 +116,12 @@ ol.renderer.webgl.Map = function(container, map) {
this.canvas_.className = 'ol-unselectable';
goog.dom.insertChildAt(container, this.canvas_, 0);
/**
* @private
* @type {boolean}
*/
this.renderedVisible_ = true;
/**
* @private
* @type {ol.Size}
@@ -143,12 +146,6 @@ ol.renderer.webgl.Map = function(container, map) {
goog.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED,
this.handleWebGLContextResourced, false, this);
/**
* @private
* @type {ol.Color}
*/
this.clearColor_ = new ol.Color(1, 1, 1, 1);
/**
* @private
* @type {{aPosition: number,
@@ -220,15 +217,15 @@ ol.renderer.webgl.Map.prototype.addLayer = function(layer) {
/**
* @param {Image} image Image.
* @param {ol.Tile} tile Tile.
* @param {number} magFilter Mag filter.
* @param {number} minFilter Min filter.
*/
ol.renderer.webgl.Map.prototype.bindImageTexture =
function(image, magFilter, minFilter) {
ol.renderer.webgl.Map.prototype.bindTileTexture =
function(tile, magFilter, minFilter) {
var gl = this.getGL();
var imageKey = image.src;
var textureCacheEntry = this.textureCache_[imageKey];
var tileKey = tile.getKey();
var textureCacheEntry = this.textureCache_[tileKey];
if (goog.isDef(textureCacheEntry)) {
gl.bindTexture(goog.webgl.TEXTURE_2D, textureCacheEntry.texture);
if (textureCacheEntry.magFilter != magFilter) {
@@ -245,7 +242,7 @@ ol.renderer.webgl.Map.prototype.bindImageTexture =
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, image);
goog.webgl.UNSIGNED_BYTE, tile.getImage());
gl.texParameteri(
goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter);
gl.texParameteri(
@@ -254,7 +251,7 @@ ol.renderer.webgl.Map.prototype.bindImageTexture =
goog.webgl.CLAMP_TO_EDGE);
gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T,
goog.webgl.CLAMP_TO_EDGE);
this.textureCache_[imageKey] = {
this.textureCache_[tileKey] = {
texture: texture,
magFilter: magFilter,
minFilter: minFilter
@@ -263,75 +260,10 @@ ol.renderer.webgl.Map.prototype.bindImageTexture =
};
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.canRotate = goog.functions.TRUE;
/**
* @param {number} value Hue value.
* @return {!goog.vec.Mat4.Float32} Matrix.
*/
ol.renderer.webgl.Map.prototype.createHueRotateMatrix = function(value) {
var cosHue = Math.cos(value);
var sinHue = Math.sin(value);
var v00 = 0.213 + cosHue * 0.787 - sinHue * 0.213;
var v01 = 0.715 - cosHue * 0.715 - sinHue * 0.715;
var v02 = 0.072 - cosHue * 0.072 + sinHue * 0.928;
var v03 = 0;
var v10 = 0.213 - cosHue * 0.213 + sinHue * 0.143;
var v11 = 0.715 + cosHue * 0.285 + sinHue * 0.140;
var v12 = 0.072 - cosHue * 0.072 - sinHue * 0.283;
var v13 = 0;
var v20 = 0.213 - cosHue * 0.213 - sinHue * 0.787;
var v21 = 0.715 - cosHue * 0.715 + sinHue * 0.715;
var v22 = 0.072 + cosHue * 0.928 + sinHue * 0.072;
var v23 = 0;
var v30 = 0;
var v31 = 0;
var v32 = 0;
var v33 = 1;
var matrix = goog.vec.Mat4.createFloat32();
goog.vec.Mat4.setFromValues(matrix,
v00, v10, v20, v30,
v01, v11, v21, v31,
v02, v12, v22, v32,
v03, v13, v23, v33);
return matrix;
};
/**
* @param {number} value Brightness value.
* @return {!goog.vec.Mat4.Float32} Matrix.
*/
ol.renderer.webgl.Map.prototype.createBrightnessMatrix = function(value) {
var matrix = goog.vec.Mat4.createFloat32Identity();
goog.vec.Mat4.setColumnValues(matrix, 3, value, value, value, 1);
return matrix;
};
/**
* @param {number} value Contrast value.
* @return {!goog.vec.Mat4.Float32} Matrix.
*/
ol.renderer.webgl.Map.prototype.createContrastMatrix = function(value) {
var matrix = goog.vec.Mat4.createFloat32();
goog.vec.Mat4.setDiagonalValues(matrix, value, value, value, 1);
var translateValue = (-0.5 * value + 0.5);
goog.vec.Mat4.setColumnValues(matrix, 3,
translateValue, translateValue, translateValue, 1);
return matrix;
};
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.createLayerRenderer = function(layer) {
var gl = this.getGL();
if (layer instanceof ol.layer.TileLayer) {
return new ol.renderer.webgl.TileLayer(this, layer);
} else {
@@ -341,38 +273,6 @@ ol.renderer.webgl.Map.prototype.createLayerRenderer = function(layer) {
};
/**
* @param {number} value Saturation value.
* @return {!goog.vec.Mat4.Float32} Matrix.
*/
ol.renderer.webgl.Map.prototype.createSaturateMatrix = function(value) {
var v00 = 0.213 + 0.787 * value;
var v01 = 0.715 - 0.715 * value;
var v02 = 0.072 - 0.072 * value;
var v03 = 0;
var v10 = 0.213 - 0.213 * value;
var v11 = 0.715 + 0.285 * value;
var v12 = 0.072 - 0.072 * value;
var v13 = 0;
var v20 = 0.213 - 0.213 * value;
var v21 = 0.715 - 0.715 * value;
var v22 = 0.072 + 0.928 * value;
var v23 = 0;
var v30 = 0;
var v31 = 0;
var v32 = 0;
var v33 = 1;
var matrix = goog.vec.Mat4.createFloat32();
goog.vec.Mat4.setFromValues(matrix,
v00, v10, v20, v30,
v01, v11, v21, v31,
v02, v12, v22, v32,
v03, v13, v23, v33);
return matrix;
};
/**
* @inheritDoc
*/
@@ -464,21 +364,6 @@ ol.renderer.webgl.Map.prototype.getShader = function(shaderObject) {
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.handleBackgroundColorChanged = function() {
var backgroundColor = this.getMap().getBackgroundColor();
this.clearColor_ = new ol.Color(
backgroundColor.r / 255,
backgroundColor.g / 255,
backgroundColor.b / 255,
backgroundColor.a / 255);
this.getMap().render();
};
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.handleCenterChanged = function() {
goog.base(this, 'handleCenterChanged');
this.getMap().render();
};
@@ -492,33 +377,6 @@ ol.renderer.webgl.Map.prototype.handleLayerRendererChange = function(event) {
};
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.handleResolutionChanged = function() {
goog.base(this, 'handleResolutionChanged');
this.getMap().render();
};
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.handleRotationChanged = function() {
goog.base(this, 'handleRotationChanged');
this.getMap().render();
};
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.handleSizeChanged = function() {
goog.base(this, 'handleSizeChanged');
this.getMap().render();
};
/**
* @param {goog.events.Event} event Event.
* @protected
@@ -565,11 +423,11 @@ ol.renderer.webgl.Map.prototype.initializeGL_ = function() {
/**
* @param {Image} image Image.
* @return {boolean} Is image texture loaded.
* @param {ol.Tile} tile Tile.
* @return {boolean} Is tile texture loaded.
*/
ol.renderer.webgl.Map.prototype.isImageTextureLoaded = function(image) {
return image.src in this.textureCache_;
ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) {
return tile.getKey() in this.textureCache_;
};
@@ -601,40 +459,38 @@ ol.renderer.webgl.Map.prototype.removeLayerRenderer = function(layer) {
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.renderFrame = function(time) {
ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
if (!this.getMap().isDef()) {
return;
var gl = this.getGL();
if (goog.isNull(frameState)) {
if (this.renderedVisible_) {
goog.style.showElement(this.canvas_, false);
this.renderedVisible_ = false;
}
return false;
}
var requestRenderFrame = false;
this.forEachReadyVisibleLayer(function(layer, layerRenderer) {
if (layerRenderer.renderFrame(time)) {
requestRenderFrame = true;
goog.array.forEach(frameState.layersArray, function(layer) {
var layerState = frameState.layerStates[goog.getUid(layer)];
if (!layerState.visible || !layerState.ready) {
return;
}
});
var layerRenderer = this.getLayerRenderer(layer);
layerRenderer.renderFrame(frameState, layerState);
}, this);
var size = /** @type {ol.Size} */ this.getMap().getSize();
var size = frameState.size;
if (!this.canvasSize_.equals(size)) {
this.canvas_.width = size.width;
this.canvas_.height = size.height;
this.canvasSize_ = size;
}
var animate = false;
this.forEachReadyVisibleLayer(function(layer, layerRenderer) {
if (layerRenderer.renderFrame(time)) {
animate = true;
}
});
var gl = this.getGL();
gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, null);
gl.clearColor(this.clearColor_.r, this.clearColor_.g, this.clearColor_.b,
this.clearColor_.a);
var clearColor = frameState.backgroundColor;
gl.clearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
gl.clear(goog.webgl.COLOR_BUFFER_BIT);
gl.enable(goog.webgl.BLEND);
gl.viewport(0, 0, size.width, size.height);
@@ -674,28 +530,28 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(time) {
this.locations_.aTexCoord, 2, goog.webgl.FLOAT, false, 16, 8);
gl.uniform1i(this.locations_.uTexture, 0);
this.forEachReadyVisibleLayer(function(layer, layerRenderer) {
goog.array.forEach(frameState.layersArray, function(layer) {
var layerState = frameState.layerStates[goog.getUid(layer)];
if (!layerState.visible || !layerState.ready) {
return;
}
var layerRenderer = this.getLayerRenderer(layer);
gl.uniformMatrix4fv(
this.locations_.uMatrix, false, layerRenderer.getMatrix());
var hueRotateMatrix = this.createHueRotateMatrix(layer.getHue());
var saturateMatrix = this.createSaturateMatrix(layer.getSaturation());
var brightnessMatrix = this.createBrightnessMatrix(layer.getBrightness());
var contrastMatrix = this.createContrastMatrix(layer.getContrast());
var colorMatrix = goog.vec.Mat4.createFloat32Identity();
goog.vec.Mat4.multMat(colorMatrix, contrastMatrix, colorMatrix);
goog.vec.Mat4.multMat(colorMatrix, brightnessMatrix, colorMatrix);
goog.vec.Mat4.multMat(colorMatrix, saturateMatrix, colorMatrix);
goog.vec.Mat4.multMat(colorMatrix, hueRotateMatrix, colorMatrix);
gl.uniformMatrix4fv(this.locations_.uColorMatrix, false, colorMatrix);
gl.uniformMatrix4fv(
this.locations_.uColorMatrix, false, layerRenderer.getColorMatrix());
gl.uniform1f(this.locations_.uOpacity, layer.getOpacity());
gl.bindTexture(goog.webgl.TEXTURE_2D, layerRenderer.getTexture());
gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4);
}, this);
if (requestRenderFrame) {
this.getMap().requestRenderFrame();
if (!this.renderedVisible_) {
goog.style.showElement(this.canvas_, true);
this.renderedVisible_ = true;
}
this.calculateMatrices2D(frameState);
};
-6
View File
@@ -3,12 +3,6 @@ goog.provide('ol.renderer.webgl');
goog.require('ol.webgl');
/**
* @define {boolean} Free resources immediately.
*/
ol.renderer.webgl.FREE_RESOURCES_IMMEDIATELY = false;
/**
* @return {boolean} Is supported.
*/
+106 -143
View File
@@ -1,7 +1,5 @@
// FIXME large resolutions lead to too large framebuffers :-(
// FIXME animated shaders! check in redraw
// FIXME throttle texture uploads
// FIXME prioritize texture uploads
goog.provide('ol.renderer.webgl.TileLayer');
goog.provide('ol.renderer.webgl.tilelayerrenderer');
@@ -10,13 +8,14 @@ goog.provide('ol.renderer.webgl.tilelayerrenderer.shader.Vertex');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.debug.Logger');
goog.require('goog.events.EventType');
goog.require('goog.object');
goog.require('goog.structs.PriorityQueue');
goog.require('goog.vec.Mat4');
goog.require('goog.vec.Vec4');
goog.require('goog.webgl');
goog.require('ol.Coordinate');
goog.require('ol.FrameState');
goog.require('ol.Size');
goog.require('ol.TileState');
goog.require('ol.layer.TileLayer');
@@ -88,14 +87,6 @@ ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) {
goog.base(this, mapRenderer, tileLayer);
if (goog.DEBUG) {
/**
* @inheritDoc
*/
this.logger = goog.debug.Logger.getLogger(
'ol.renderer.webgl.tilelayerrenderer.' + goog.getUid(this));
}
/**
* @private
* @type {ol.renderer.webgl.FragmentShader}
@@ -145,7 +136,7 @@ ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) {
/**
* @private
* @type {goog.vec.Mat4.AnyType}
* @type {!goog.vec.Mat4.Number}
*/
this.matrix_ = goog.vec.Mat4.createNumber();
@@ -166,11 +157,12 @@ goog.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer);
/**
* @param {ol.FrameState} frameState Frame state.
* @param {number} framebufferDimension Framebuffer dimension.
* @private
*/
ol.renderer.webgl.TileLayer.prototype.bindFramebuffer_ =
function(framebufferDimension) {
function(frameState, framebufferDimension) {
var mapRenderer = this.getMapRenderer();
var gl = mapRenderer.getGL();
@@ -178,33 +170,14 @@ ol.renderer.webgl.TileLayer.prototype.bindFramebuffer_ =
if (!goog.isDef(this.framebufferDimension_) ||
this.framebufferDimension_ != framebufferDimension) {
if (goog.DEBUG) {
this.logger.info('re-sizing framebuffer');
}
if (ol.renderer.webgl.FREE_RESOURCES_IMMEDIATELY) {
if (goog.DEBUG) {
this.logger.info('freeing WebGL resources');
}
if (!gl.isContextLost()) {
gl.deleteFramebuffer(this.framebuffer_);
gl.deleteTexture(this.texture_);
}
} else {
var map = this.getMap();
goog.events.listenOnce(
map,
ol.MapEventType.POSTRENDER,
goog.partial(function(gl, framebuffer, texture) {
if (goog.DEBUG) {
this.logger.info('freeing WebGL resources on postrender');
}
if (!gl.isContextLost()) {
gl.deleteFramebuffer(framebuffer);
gl.deleteTexture(texture);
}
}, gl, this.framebuffer_, this.texture_));
}
var map = this.getMap();
frameState.postRenderFunctions.push(
goog.partial(function(gl, framebuffer, texture) {
if (!gl.isContextLost()) {
gl.deleteFramebuffer(framebuffer);
gl.deleteTexture(texture);
}
}, gl, this.framebuffer_, this.texture_));
var texture = gl.createTexture();
gl.bindTexture(goog.webgl.TEXTURE_2D, texture);
@@ -247,15 +220,6 @@ ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() {
};
/**
* @return {ol.layer.TileLayer} Layer.
* @inheritDoc
*/
ol.renderer.webgl.TileLayer.prototype.getLayer = function() {
return /** @type {ol.layer.TileLayer} */ goog.base(this, 'getLayer');
};
/**
* @inheritDoc
*/
@@ -272,6 +236,14 @@ ol.renderer.webgl.TileLayer.prototype.getTexture = function() {
};
/**
* @return {ol.layer.TileLayer} Tile layer.
*/
ol.renderer.webgl.TileLayer.prototype.getTileLayer = function() {
return /** @type {ol.layer.TileLayer} */ (this.getLayer());
};
/**
* @inheritDoc
*/
@@ -287,28 +259,22 @@ ol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() {
/**
* @inheritDoc
*/
ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
var requestRenderFrame = false;
ol.renderer.webgl.TileLayer.prototype.renderFrame =
function(frameState, layerState) {
var mapRenderer = this.getMapRenderer();
var map = this.getMap();
var gl = mapRenderer.getGL();
goog.asserts.assert(map.isDef());
var mapCenter = map.getCenter();
var mapExtent = map.getExtent();
var mapResolution = /** @type {number} */ map.getResolution();
var mapRotatedExtent = map.getRotatedExtent();
var mapRotation = map.getRotation();
var view2DState = frameState.view2DState;
var center = view2DState.center;
var tileLayer = this.getLayer();
var tileLayer = this.getTileLayer();
var tileSource = tileLayer.getTileSource();
var tileGrid = tileSource.getTileGrid();
var z = tileGrid.getZForResolution(mapResolution);
var z = tileGrid.getZForResolution(view2DState.resolution);
var tileResolution = tileGrid.getResolution(z);
var tileRange = tileGrid.getTileRangeForExtentAndResolution(
mapRotatedExtent, tileResolution);
frameState.extent, tileResolution);
var framebufferExtent;
@@ -337,7 +303,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
minX + framebufferExtentSize.width,
minY + framebufferExtentSize.height);
this.bindFramebuffer_(framebufferDimension);
this.bindFramebuffer_(frameState, framebufferDimension);
gl.viewport(0, 0, framebufferDimension, framebufferDimension);
gl.clearColor(0, 0, 0, 0);
@@ -382,65 +348,73 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
* @type {Object.<number, Object.<string, ol.Tile>>}
*/
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
/**
* @type {Array.<Image>}
*/
var imagesToLoad = [];
var findInterimTiles = function(z, tileRange) {
// FIXME this could be more efficient about filling partial holes
var fullyCovered = true;
var tile, tileCoord, tileCoordKey, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
tileCoordKey = tileCoord.toString();
if (tilesToDrawByZ[z] && tilesToDrawByZ[z][tileCoordKey]) {
return;
}
tile = tileSource.getTile(tileCoord);
if (!goog.isNull(tile) &&
tile.getState() == ol.TileState.LOADED &&
mapRenderer.isTileTextureLoaded(tile)) {
if (!tilesToDrawByZ[z]) {
tilesToDrawByZ[z] = {};
}
tilesToDrawByZ[z][tileCoordKey] = tile;
} else {
fullyCovered = false;
}
}
}
return fullyCovered;
};
var tilesToLoad = new goog.structs.PriorityQueue();
var allTilesLoaded = true;
var deltaX, deltaY, priority, tile, tileCenter, tileCoord, tileState, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tilesToDrawByZ[z] = {};
tileRange.forEachTileCoord(z, function(tileCoord) {
var tile = tileSource.getTile(tileCoord);
if (goog.isNull(tile)) {
return;
}
var tileState = tile.getState();
if (tileState == ol.TileState.IDLE) {
tile.load();
} else if (tileState == ol.TileState.LOADED) {
var image = tile.getImage();
if (mapRenderer.isImageTextureLoaded(image)) {
tilesToDrawByZ[z][tileCoord.toString()] = tile;
return;
} else {
imagesToLoad.push(image);
tileCoord = new ol.TileCoord(z, x, y);
tile = tileSource.getTile(tileCoord);
if (goog.isNull(tile)) {
continue;
}
} else if (tileState == ol.TileState.ERROR) {
return;
tileState = tile.getState();
if (tileState == ol.TileState.IDLE) {
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
frameState.tileQueue.enqueue(tile, tileCenter, tileResolution);
} else if (tileState == ol.TileState.LOADED) {
if (mapRenderer.isTileTextureLoaded(tile)) {
tilesToDrawByZ[z][tileCoord.toString()] = tile;
continue;
} else {
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
deltaX = tileCenter.x - center.x;
deltaY = tileCenter.y - center.y;
priority = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
tilesToLoad.enqueue(priority, tile);
}
} else if (tileState == ol.TileState.ERROR) {
continue;
}
allTilesLoaded = false;
tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles);
}
allTilesLoaded = false;
// FIXME this could be more efficient about filling partial holes
tileGrid.forEachTileCoordParentTileRange(
tileCoord,
function(z, tileRange) {
var fullyCovered = true;
tileRange.forEachTileCoord(z, function(tileCoord) {
var tileCoordKey = tileCoord.toString();
if (tilesToDrawByZ[z] && tilesToDrawByZ[z][tileCoordKey]) {
return;
}
var tile = tileSource.getTile(tileCoord);
if (!goog.isNull(tile) &&
tile.getState() == ol.TileState.LOADED) {
if (!tilesToDrawByZ[z]) {
tilesToDrawByZ[z] = {};
}
tilesToDrawByZ[z][tileCoordKey] = tile;
} else {
fullyCovered = false;
}
});
return fullyCovered;
});
}, this);
}
/** @type {Array.<number>} */
var zs = goog.array.map(goog.object.getKeys(tilesToDrawByZ), Number);
@@ -457,29 +431,22 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
framebufferExtentSize.height - 1;
goog.vec.Vec4.setFromValues(uTileOffset, sx, sy, tx, ty);
gl.uniform4fv(this.locations_.uTileOffset, uTileOffset);
mapRenderer.bindImageTexture(
tile.getImage(), goog.webgl.LINEAR, goog.webgl.LINEAR);
mapRenderer.bindTileTexture(tile, goog.webgl.LINEAR, goog.webgl.LINEAR);
gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4);
}, this);
}, this);
if (!goog.array.isEmpty(imagesToLoad)) {
goog.events.listenOnce(
map,
ol.MapEventType.POSTRENDER,
goog.partial(function(mapRenderer, imagesToLoad) {
if (goog.DEBUG) {
this.logger.info(
'uploading ' + imagesToLoad.length + ' textures');
if (!tilesToLoad.isEmpty()) {
frameState.postRenderFunctions.push(
goog.partial(function(mapRenderer, tilesToLoad) {
var i, tile;
// FIXME determine a suitable number of textures to upload per frame
for (i = 0; !tilesToLoad.isEmpty() && i < 4; ++i) {
tile = /** @type {ol.Tile} */ (tilesToLoad.remove());
mapRenderer.bindTileTexture(
tile, goog.webgl.LINEAR, goog.webgl.LINEAR);
}
goog.array.forEach(imagesToLoad, function(image) {
mapRenderer.bindImageTexture(
image, goog.webgl.LINEAR, goog.webgl.LINEAR);
});
if (goog.DEBUG) {
this.logger.info('uploaded textures');
}
}, mapRenderer, imagesToLoad));
}, mapRenderer, tilesToLoad));
}
if (allTilesLoaded) {
@@ -488,25 +455,23 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
} else {
this.renderedTileRange_ = null;
this.renderedFramebufferExtent_ = null;
requestRenderFrame = true;
frameState.animate = true;
}
}
goog.vec.Mat4.makeIdentity(this.matrix_);
goog.vec.Mat4.translate(this.matrix_,
(mapCenter.x - framebufferExtent.minX) /
(view2DState.center.x - framebufferExtent.minX) /
(framebufferExtent.maxX - framebufferExtent.minX),
(mapCenter.y - framebufferExtent.minY) /
(view2DState.center.y - framebufferExtent.minY) /
(framebufferExtent.maxY - framebufferExtent.minY),
0);
if (goog.isDef(mapRotation)) {
goog.vec.Mat4.rotateZ(this.matrix_, mapRotation);
}
goog.vec.Mat4.rotateZ(this.matrix_, view2DState.rotation);
goog.vec.Mat4.scale(this.matrix_,
(mapExtent.maxX - mapExtent.minX) /
frameState.size.width * view2DState.resolution /
(framebufferExtent.maxX - framebufferExtent.minX),
(mapExtent.maxY - mapExtent.minY) /
frameState.size.height * view2DState.resolution /
(framebufferExtent.maxY - framebufferExtent.minY),
1);
goog.vec.Mat4.translate(this.matrix_,
@@ -514,6 +479,4 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = function(time) {
-0.5,
0);
return requestRenderFrame;
};