diff --git a/src/data/bucket/symbol_bucket.js b/src/data/bucket/symbol_bucket.js index afb5deb3887..da043b12cca 100644 --- a/src/data/bucket/symbol_bucket.js +++ b/src/data/bucket/symbol_bucket.js @@ -115,18 +115,22 @@ function addVertex(array, anchorX, anchorY, ox, oy, tx, ty, sizeVertex, labelmin // a_data tx, // x coordinate of symbol on glyph atlas texture ty, // y coordinate of symbol on glyph atlas texture - packUint8ToFloat( - (labelminzoom || 0) * 10, // labelminzoom - 0 // unused 8 bits - ), - 0, // unused 16 bits - - // a_size sizeVertex ? sizeVertex[0] : undefined, sizeVertex ? sizeVertex[1] : undefined ); } +function addDynamicAttributes(dynamicLayoutVertexArray, p, angle, placementZoom) { + const twoPi = Math.PI * 2; + const angleAndZoom = packUint8ToFloat( + ((angle + twoPi) % twoPi) / twoPi * 255, + placementZoom * 10); + dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angleAndZoom); + dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angleAndZoom); + dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angleAndZoom); + dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angleAndZoom); +} + function addCollisionBoxVertex(layoutVertexArray, point, anchor, extrude, maxZoom, placementZoom) { return layoutVertexArray.emplaceBack( // pos @@ -184,25 +188,7 @@ class SymbolBucket { // Set up 'program interfaces' dynamically based on the layer's style // properties (specifically its text-size properties). const layer = this.layers[0]; - this.symbolInterfaces = { - glyph: util.extend({}, symbolInterfaces.glyph, { - layoutAttributes: [].concat( - symbolInterfaces.glyph.layoutAttributes, - getSizeAttributeDeclarations(layer, 'text-size') - ) - }), - icon: util.extend({}, symbolInterfaces.icon, { - layoutAttributes: [].concat( - symbolInterfaces.icon.layoutAttributes, - getSizeAttributeDeclarations(layer, 'icon-size') - ) - }), - collisionBox: util.extend({}, symbolInterfaces.collisionBox, { - layoutAttributes: [].concat( - symbolInterfaces.collisionBox.layoutAttributes - ) - }) - }; + this.symbolInterfaces = symbolInterfaces; // deserializing a bucket created on a worker thread if (options.arrays) { @@ -748,10 +734,7 @@ class SymbolBucket { addVertex(layoutVertexArray, labelAnchor.x, labelAnchor.y, bl.x, y + bl.y, tex.x, tex.y + tex.h, sizeVertex, placementZoom); addVertex(layoutVertexArray, labelAnchor.x, labelAnchor.y, br.x, y + br.y, tex.x + tex.w, tex.y + tex.h, sizeVertex, placementZoom); - dynamicLayoutVertexArray.emplaceBack(labelAnchor.x, labelAnchor.y, 0); - dynamicLayoutVertexArray.emplaceBack(labelAnchor.x, labelAnchor.y, 0); - dynamicLayoutVertexArray.emplaceBack(labelAnchor.x, labelAnchor.y, 0); - dynamicLayoutVertexArray.emplaceBack(labelAnchor.x, labelAnchor.y, 0); + addDynamicAttributes(dynamicLayoutVertexArray, labelAnchor, 0, placementZoom); elementArray.emplaceBack(index, index + 1, index + 2); elementArray.emplaceBack(index + 1, index + 2, index + 3); @@ -942,32 +925,6 @@ function getSizeData(tileZoom, layer, sizeProperty) { return sizeData; } -function getSizeAttributeDeclarations(layer, sizeProperty) { - // The contents of the a_size vertex attribute depend on the type of - // property value for {text,icon}-size. - if ( - layer.isLayoutValueZoomConstant(sizeProperty) && - !layer.isLayoutValueFeatureConstant(sizeProperty) - ) { - // source function: one size value per vertex - return [{ - name: 'a_size', components: 1, type: 'Uint16' - }]; - } else if ( - !layer.isLayoutValueZoomConstant(sizeProperty) && - !layer.isLayoutValueFeatureConstant(sizeProperty) - ) { - // composite function: - // [ text-size(lowerZoomStop, feature), - // text-size(upperZoomStop, feature)] - return [{ - name: 'a_size', components: 2, type: 'Uint16' - }]; - } - // constant or camera function - return []; -} - function getSizeVertexData(layer, tileZoom, stopZoomLevels, sizeProperty, featureProperties) { if ( layer.isLayoutValueZoomConstant(sizeProperty) && @@ -998,4 +955,6 @@ SymbolBucket.programInterfaces = symbolInterfaces; // eg the max valid UInt16 is 65,535 SymbolBucket.MAX_INSTANCES = 65535; +SymbolBucket.addDynamicAttributes = addDynamicAttributes; + module.exports = SymbolBucket; diff --git a/src/shaders/symbol_icon.vertex.glsl b/src/shaders/symbol_icon.vertex.glsl index ef5cf2a184e..4d59bb64e8b 100644 --- a/src/shaders/symbol_icon.vertex.glsl +++ b/src/shaders/symbol_icon.vertex.glsl @@ -1,9 +1,9 @@ +const float PI = 3.141592653589793; + attribute vec4 a_pos_offset; attribute vec4 a_data; attribute vec3 a_projected_pos; -// icon-size data (see symbol_sdf.vertex.glsl for more) -attribute vec2 a_size; uniform bool u_is_size_zoom_constant; uniform bool u_is_size_feature_constant; uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function @@ -33,8 +33,11 @@ void main() { vec2 a_offset = a_pos_offset.zw; vec2 a_tex = a_data.xy; - mediump vec2 label_data = unpack_float(a_data[2]); - mediump float a_labelminzoom = label_data[0]; + vec2 a_size = a_data.zw; + + highp vec2 angle_labelminzoom = unpack_float(a_projected_pos[2]); + highp float segment_angle = -angle_labelminzoom[0] / 255.0 * 2.0 * PI; + mediump float a_labelminzoom = angle_labelminzoom[1]; float size; if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { @@ -59,7 +62,6 @@ void main() { float fontScale = u_is_text ? size / 24.0 : size; - highp float segment_angle = -a_projected_pos[2]; highp float angle_sin = sin(segment_angle); highp float angle_cos = cos(segment_angle); mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); diff --git a/src/shaders/symbol_sdf.vertex.glsl b/src/shaders/symbol_sdf.vertex.glsl index ac196bae4f9..006e22aa456 100644 --- a/src/shaders/symbol_sdf.vertex.glsl +++ b/src/shaders/symbol_sdf.vertex.glsl @@ -1,3 +1,5 @@ +const float PI = 3.141592653589793; + // NOTE: the a_data attribute in this shader is manually bound (see https://github.com/mapbox/mapbox-gl-js/issues/4607). // If removing or renaming a_data, revisit the manual binding in painter.js accordingly. attribute vec4 a_pos_offset; @@ -11,7 +13,6 @@ attribute vec3 a_projected_pos; // For composite functions: // [ text-size(lowerZoomStop, feature), // text-size(upperZoomStop, feature) ] -attribute vec2 a_size; uniform bool u_is_size_zoom_constant; uniform bool u_is_size_feature_constant; uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function @@ -51,9 +52,11 @@ void main() { vec2 a_offset = a_pos_offset.zw; vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; - mediump vec2 label_data = unpack_float(a_data[2]); - mediump float a_labelminzoom = label_data[0]; + highp vec2 angle_labelminzoom = unpack_float(a_projected_pos[2]); + highp float segment_angle = -angle_labelminzoom[0] / 255.0 * 2.0 * PI; + mediump float a_labelminzoom = angle_labelminzoom[1]; if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { v_size = mix(a_size[0], a_size[1], u_size_t) / 10.0; @@ -82,7 +85,6 @@ void main() { float fontScale = u_is_text ? v_size / 24.0 : v_size; - highp float segment_angle = -a_projected_pos[2]; highp float angle_sin = sin(segment_angle); highp float angle_cos = cos(segment_angle); mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); diff --git a/src/symbol/projection.js b/src/symbol/projection.js index 177b81528b6..1acbc41d352 100644 --- a/src/symbol/projection.js +++ b/src/symbol/projection.js @@ -5,6 +5,7 @@ const assert = require('assert'); const mat4 = require('@mapbox/gl-matrix').mat4; const vec4 = require('@mapbox/gl-matrix').vec4; const symbolSize = require('./symbol_size'); +const addDynamicAttributes = require('../data/bucket/symbol_bucket').addDynamicAttributes; module.exports = { updateLineLabels: updateLineLabels, @@ -101,7 +102,7 @@ function project(point, matrix) { return new Point(pos[0] / pos[3], pos[1] / pos[3]); } -function isVisible(anchorPos, symbol, clippingBuffer, painter) { +function isVisible(anchorPos, placementZoom, clippingBuffer, painter) { const x = anchorPos[0] / anchorPos[3]; const y = anchorPos[1] / anchorPos[3]; const inPaddedViewport = ( @@ -109,7 +110,7 @@ function isVisible(anchorPos, symbol, clippingBuffer, painter) { x <= clippingBuffer[0] && y >= -clippingBuffer[1] && y <= clippingBuffer[1]); - return inPaddedViewport && painter.frameHistory.isVisible(symbol.placementZoom); + return inPaddedViewport && painter.frameHistory.isVisible(placementZoom); } /* @@ -133,12 +134,13 @@ function updateLineLabels(bucket, posMatrix, painter, isText, labelPlaneMatrix, for (let s = 0; s < placedSymbols.length; s++) { const symbol = placedSymbols.get(s); + const placementZoom = symbol.placementZoom; const anchorPos = [symbol.anchorX, symbol.anchorY, 0, 1]; vec4.transformMat4(anchorPos, anchorPos, posMatrix); // Don't bother calculating the correct point for invisible labels. - if (!isVisible(anchorPos, symbol, clippingBuffer, painter)) { + if (!isVisible(anchorPos, placementZoom, clippingBuffer, painter)) { hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray); continue; } @@ -178,7 +180,7 @@ function updateLineLabels(bucket, posMatrix, painter, isText, labelPlaneMatrix, processDirection(returnGlyphs, glyphsForward, 1, flip, symbol, lineVertexArray, labelPlaneMatrix, fontScale) && processDirection(returnGlyphs, glyphsBackward, -1, flip, symbol, lineVertexArray, labelPlaneMatrix, fontScale)) { for (const glyph of returnGlyphs) { - addGlyph(glyph.point, glyph.angle, dynamicLayoutVertexArray); + addDynamicAttributes(dynamicLayoutVertexArray, glyph.point, glyph.angle, placementZoom); } } else { hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray); @@ -253,12 +255,6 @@ const offscreenPoint = new Point(-Infinity, -Infinity); // because the dynamic buffer is paired with a static buffer that doesn't get updated. function hideGlyphs(num, dynamicLayoutVertexArray) { for (let i = 0; i < num; i++) { - addGlyph(offscreenPoint, 0, dynamicLayoutVertexArray); + addDynamicAttributes(dynamicLayoutVertexArray, offscreenPoint, 0, 25); } } -function addGlyph(p, angle, dynamicLayoutVertexArray) { - dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angle); - dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angle); - dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angle); - dynamicLayoutVertexArray.emplaceBack(p.x, p.y, angle); -} diff --git a/test/integration/render-tests/icon-text-fit/placement-line/expected.png b/test/integration/render-tests/icon-text-fit/placement-line/expected.png index f65ef8f89a2..0bf2f3ccd53 100644 Binary files a/test/integration/render-tests/icon-text-fit/placement-line/expected.png and b/test/integration/render-tests/icon-text-fit/placement-line/expected.png differ