diff --git a/js/data/symbol_bucket.js b/js/data/symbol_bucket.js index cae8d29635b..37d548d1a6f 100644 --- a/js/data/symbol_bucket.js +++ b/js/data/symbol_bucket.js @@ -117,6 +117,7 @@ SymbolBucket.prototype.addFeatures = function(collisionTile, stacks, icons) { this.tilePixelRatio = tileExtent / tileSize; this.compareText = {}; this.symbolInstances = []; + this.iconsNeedLinear = false; var layout = this.layoutProperties; var features = this.features; @@ -200,6 +201,9 @@ SymbolBucket.prototype.addFeatures = function(collisionTile, stacks, icons) { } else if (this.sdfIcons !== image.sdf) { console.warn('Style sheet warning: Cannot mix SDF and non-SDF icons in one buffer'); } + if (image.pixelRatio !== 1) { + this.iconsNeedLinear = true; + } } } else { shapedIcon = null; @@ -307,7 +311,8 @@ SymbolBucket.prototype.placeFeatures = function(collisionTile, buffers, collisio var elementGroups = this.elementGroups = { glyph: new ElementGroups(buffers.glyphVertex, buffers.glyphElement), icon: new ElementGroups(buffers.iconVertex, buffers.iconElement), - sdfIcons: this.sdfIcons + sdfIcons: this.sdfIcons, + iconsNeedLinear: this.iconsNeedLinear }; var layout = this.layoutProperties; diff --git a/js/render/draw_symbol.js b/js/render/draw_symbol.js index 46f33f97dce..ee4baaac935 100644 --- a/js/render/draw_symbol.js +++ b/js/render/draw_symbol.js @@ -40,7 +40,7 @@ function drawSymbols(painter, source, layer, coords) { posMatrix = painter.calculatePosMatrix(coords[i], source.maxzoom); painter.enableTileClippingMask(coords[i]); - drawSymbol(painter, layer, posMatrix, tile, elementGroups.icon, 'icon', elementGroups.sdfIcons); + drawSymbol(painter, layer, posMatrix, tile, elementGroups.icon, 'icon', elementGroups.sdfIcons, elementGroups.iconsNeedLinear); } for (var j = 0; j < coords.length; j++) { @@ -53,7 +53,7 @@ function drawSymbols(painter, source, layer, coords) { posMatrix = painter.calculatePosMatrix(coords[j], source.maxzoom); painter.enableTileClippingMask(coords[j]); - drawSymbol(painter, layer, posMatrix, tile, elementGroups.glyph, 'text', true); + drawSymbol(painter, layer, posMatrix, tile, elementGroups.glyph, 'text', true, false); } for (var k = 0; k < coords.length; k++) { @@ -73,7 +73,7 @@ var defaultSizes = { text: 24 }; -function drawSymbol(painter, layer, posMatrix, tile, elementGroups, prefix, sdf) { +function drawSymbol(painter, layer, posMatrix, tile, elementGroups, prefix, sdf, iconsNeedLinear) { var gl = painter.gl; posMatrix = painter.translatePosMatrix(posMatrix, tile, layer.paint[prefix + '-translate'], layer.paint[prefix + '-translate-anchor']); @@ -125,7 +125,7 @@ function drawSymbol(painter, layer, posMatrix, tile, elementGroups, prefix, sdf) texsize = [painter.glyphAtlas.width / 4, painter.glyphAtlas.height / 4]; } else { var mapMoving = painter.options.rotating || painter.options.zooming; - var iconScaled = fontScale !== 1 || browser.devicePixelRatio !== painter.spriteAtlas.pixelRatio; + var iconScaled = fontScale !== 1 || browser.devicePixelRatio !== painter.spriteAtlas.pixelRatio || iconsNeedLinear; var iconTransformed = alignedWithMap || painter.transform.pitch; painter.spriteAtlas.bind(gl, sdf || mapMoving || iconScaled || iconTransformed); vertex = tile.buffers.iconVertex; diff --git a/js/style/style.js b/js/style/style.js index 2dd0400bd06..72abb2dac23 100644 --- a/js/style/style.js +++ b/js/style/style.js @@ -23,7 +23,6 @@ function Style(stylesheet, animationLoop) { this.dispatcher = new Dispatcher(Math.max(browser.hardwareConcurrency - 1, 1), this); this.glyphAtlas = new GlyphAtlas(1024, 1024); this.spriteAtlas = new SpriteAtlas(512, 512); - this.spriteAtlas.resize(browser.devicePixelRatio); this.lineAtlas = new LineAtlas(256, 512); this._layers = {}; diff --git a/js/symbol/quads.js b/js/symbol/quads.js index 7766c4b4b99..a6eb78ec9c5 100644 --- a/js/symbol/quads.js +++ b/js/symbol/quads.js @@ -57,9 +57,9 @@ function getIconQuads(anchor, shapedIcon, boxScale, line, layout, alongLine) { var border = 1; var left = shapedIcon.left - border; - var right = left + rect.w; + var right = left + rect.w / shapedIcon.image.pixelRatio; var top = shapedIcon.top - border; - var bottom = top + rect.h; + var bottom = top + rect.h / shapedIcon.image.pixelRatio; var tl = new Point(left, top); var tr = new Point(right, top); var br = new Point(right, bottom); diff --git a/js/symbol/sprite_atlas.js b/js/symbol/sprite_atlas.js index d25b3efa573..85c84ab63ce 100644 --- a/js/symbol/sprite_atlas.js +++ b/js/symbol/sprite_atlas.js @@ -1,6 +1,7 @@ 'use strict'; var BinPack = require('./bin_pack'); +var browser = require('../util/browser'); module.exports = SpriteAtlas; function SpriteAtlas(width, height) { @@ -37,51 +38,6 @@ SpriteAtlas.prototype = { } }; -SpriteAtlas.prototype.resize = function(newRatio) { - newRatio = newRatio > 1 ? 2 : 1; - - if (this.pixelRatio === newRatio) return false; - - var oldRatio = this.pixelRatio; - this.pixelRatio = newRatio; - - if (this.canvas) { - this.canvas.width = this.width * this.pixelRatio; - this.canvas.height = this.height * this.pixelRatio; - } - - if (this.data) { - var oldData = this.data; - - this.data = false; - this.allocate(); - this.texture = false; - - var oldWidth = this.width * oldRatio; - var oldHeight = this.height * oldRatio; - var newWidth = this.width * newRatio; - var newHeight = this.height * newRatio; - - // Basic image scaling. TODO: Replace this with better image scaling. - var newImage = this.data; - var oldImage = oldData; - - for (var y = 0; y < newHeight; y++) { - var oldYOffset = Math.floor((y * oldHeight) / newHeight) * oldWidth; - var newYOffset = y * newWidth; - for (var x = 0; x < newWidth; x++) { - var oldX = Math.floor((x * oldWidth) / newWidth); - newImage[newYOffset + x] = oldImage[oldYOffset + oldX]; - } - } - - oldData = null; - this.dirty = true; - } - - return this.dirty; -}; - function copyBitmap(src, srcStride, srcX, srcY, dst, dstStride, dstX, dstY, width, height, wrap) { var srcI = srcY * srcStride + srcX; var dstI = dstY * dstStride + dstX; @@ -107,6 +63,9 @@ function copyBitmap(src, srcStride, srcX, srcY, dst, dstStride, dstX, dstY, widt SpriteAtlas.prototype.allocateImage = function(pixelWidth, pixelHeight) { + pixelWidth = pixelWidth / this.pixelRatio; + pixelHeight = pixelHeight / this.pixelRatio; + // Increase to next number divisible by 4, but at least 1. // This is so we can scale down the texture coordinates and pack them // into 2 bytes rather than 4 bytes. @@ -123,9 +82,6 @@ SpriteAtlas.prototype.allocateImage = function(pixelWidth, pixelHeight) { return rect; } - rect.originalWidth = pixelWidth; - rect.originalHeight = pixelHeight; - return rect; }; @@ -143,14 +99,12 @@ SpriteAtlas.prototype.getImage = function(name, wrap) { return null; } - var width = pos.width / pos.pixelRatio; - var height = pos.height / pos.pixelRatio; - var rect = this.allocateImage(width, height); + var rect = this.allocateImage(pos.width, pos.height); if (rect.x < 0) { return rect; } - var image = new AtlasImage(rect, width, height, pos.sdf); + var image = new AtlasImage(rect, pos.width / pos.pixelRatio, pos.height / pos.pixelRatio, pos.sdf, pos.pixelRatio / this.pixelRatio); this.images[name] = image; this.copy(rect, pos, wrap); @@ -159,6 +113,7 @@ SpriteAtlas.prototype.getImage = function(name, wrap) { }; +// Return position of a repeating fill pattern. SpriteAtlas.prototype.getPosition = function(name, repeating) { var image = this.getImage(name, repeating); var rect = image && image.rect; @@ -167,14 +122,12 @@ SpriteAtlas.prototype.getPosition = function(name, repeating) { return null; } - // When the image is repeating, get the correct position of the image, rather than the - // one rounded up to 4 pixels. - var width = repeating ? image.width : rect.w; - var height = repeating ? image.height : rect.h; + var width = image.width * image.pixelRatio; + var height = image.height * image.pixelRatio; var padding = 1; return { - size: [width, height], + size: [image.width, image.height], tl: [(rect.x + padding) / this.width, (rect.y + padding) / this.height], br: [(rect.x + padding + width) / this.width, (rect.y + padding + height) / this.height] }; @@ -194,7 +147,6 @@ SpriteAtlas.prototype.allocate = function() { SpriteAtlas.prototype.copy = function(dst, src, wrap) { - // if (!sprite->raster) return; if (!this.sprite.img.data) return; var srcImg = new Uint32Array(this.sprite.img.data.buffer); @@ -221,6 +173,14 @@ SpriteAtlas.prototype.copy = function(dst, src, wrap) { }; SpriteAtlas.prototype.setSprite = function(sprite) { + if (sprite) { + this.pixelRatio = browser.devicePixelRatio > 1 ? 2 : 1; + + if (this.canvas) { + this.canvas.width = this.width * this.pixelRatio; + this.canvas.height = this.height * this.pixelRatio; + } + } this.sprite = sprite; }; @@ -298,9 +258,10 @@ SpriteAtlas.prototype.bind = function(gl, linear) { } }; -function AtlasImage(rect, width, height, sdf) { +function AtlasImage(rect, width, height, sdf, pixelRatio) { this.rect = rect; this.width = width; this.height = height; this.sdf = sdf; + this.pixelRatio = pixelRatio; } diff --git a/package.json b/package.json index f58b0835800..36fd52703a6 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "eslint": "^1.5.0", "eslint-config-mourner": "^1.0.0", "istanbul": "^0.4.1", - "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#46c907f48d2b3b8ae6531963cdc40cb07958fd01", + "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#a6fe23c8cccda72a0afde9a87f8c6aabd4dcccba", "prova": "^2.1.2", "sinon": "^1.15.4", "st": "^1.0.0", diff --git a/test/js/symbol/quads.test.js b/test/js/symbol/quads.test.js index 0d1e7ff60ba..31f59529c90 100644 --- a/test/js/symbol/quads.test.js +++ b/test/js/symbol/quads.test.js @@ -14,6 +14,7 @@ test('getIconQuads', function(t) { left: -7, right: 8, image: { + pixelRatio: 1, rect: { w: 15, h: 11} } };