Skip to content

Commit

Permalink
pack symbol data into 8 attributes
Browse files Browse the repository at this point in the history
to fit within the minimum number of supported vertex attributes
  • Loading branch information
ansis committed Jun 12, 2017
1 parent 3738aef commit d2ea30b
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 81 deletions.
81 changes: 20 additions & 61 deletions src/data/bucket/symbol_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const symbolInterfaces = {
}
};

function addVertex(array, anchorX, anchorY, ox, oy, tx, ty, sizeVertex, labelminzoom) {
function addVertex(array, anchorX, anchorY, ox, oy, tx, ty, sizeVertex) {
array.emplaceBack(
// a_pos_offset
anchorX,
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -743,15 +729,12 @@ class SymbolBucket {
const index = segment.vertexLength;

const y = symbol.glyphOffsetY;
addVertex(layoutVertexArray, labelAnchor.x, labelAnchor.y, tl.x, y + tl.y, tex.x, tex.y, sizeVertex, placementZoom);
addVertex(layoutVertexArray, labelAnchor.x, labelAnchor.y, tr.x, y + tr.y, tex.x + tex.w, tex.y, sizeVertex, placementZoom);
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);
addVertex(layoutVertexArray, labelAnchor.x, labelAnchor.y, tl.x, y + tl.y, tex.x, tex.y, sizeVertex);
addVertex(layoutVertexArray, labelAnchor.x, labelAnchor.y, tr.x, y + tr.y, tex.x + tex.w, tex.y, sizeVertex);
addVertex(layoutVertexArray, labelAnchor.x, labelAnchor.y, bl.x, y + bl.y, tex.x, tex.y + tex.h, sizeVertex);
addVertex(layoutVertexArray, labelAnchor.x, labelAnchor.y, br.x, y + br.y, tex.x + tex.w, tex.y + tex.h, sizeVertex);

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);
Expand Down Expand Up @@ -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) &&
Expand Down Expand Up @@ -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;
12 changes: 7 additions & 5 deletions src/shaders/symbol_icon.vertex.glsl
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
10 changes: 6 additions & 4 deletions src/shaders/symbol_sdf.vertex.glsl
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 7 additions & 11 deletions src/symbol/projection.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -101,15 +102,15 @@ 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 = (
x >= -clippingBuffer[0] &&
x <= clippingBuffer[0] &&
y >= -clippingBuffer[1] &&
y <= clippingBuffer[1]);
return inPaddedViewport && painter.frameHistory.isVisible(symbol.placementZoom);
return inPaddedViewport && painter.frameHistory.isVisible(placementZoom);
}

/*
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d2ea30b

Please sign in to comment.