diff --git a/js/data/array_group.js b/js/data/array_group.js index e0adab1b334..f8faeb86293 100644 --- a/js/data/array_group.js +++ b/js/data/array_group.js @@ -1,6 +1,7 @@ 'use strict'; const util = require('../util/util'); +const ProgramConfiguration = require('./program_configuration'); class Segment { constructor(vertexOffset, primitiveOffset) { @@ -31,7 +32,9 @@ class Segment { * @private */ class ArrayGroup { - constructor(programInterface, programConfigurations) { + constructor(programInterface, layers, zoom) { + this.globalProperties = {zoom}; + const LayoutVertexArrayType = programInterface.layoutVertexArrayType; this.layoutVertexArray = new LayoutVertexArrayType(); @@ -41,12 +44,17 @@ class ArrayGroup { const ElementArrayType2 = programInterface.elementArrayType2; if (ElementArrayType2) this.elementArray2 = new ElementArrayType2(); - this.paintVertexArrays = util.mapObject(programConfigurations, (programConfiguration) => { + this.layerData = {}; + for (const layer of layers) { + const programConfiguration = ProgramConfiguration.createDynamic( + programInterface.paintAttributes || [], layer, zoom); const PaintVertexArrayType = programConfiguration.paintVertexArrayType(); - const paintVertexArray = new PaintVertexArrayType(); - paintVertexArray.programConfiguration = programConfiguration; - return paintVertexArray; - }); + this.layerData[layer.id] = { + layer: layer, + programConfiguration: programConfiguration, + paintVertexArray: new PaintVertexArrayType() + }; + } this.segments = []; this.segments2 = []; @@ -70,14 +78,14 @@ class ArrayGroup { return segment; } - populatePaintArrays(layers, globalProperties, featureProperties) { - for (const layer of layers) { - const paintArray = this.paintVertexArrays[layer.id]; - paintArray.programConfiguration.populatePaintArray( - layer, - paintArray, + populatePaintArrays(featureProperties) { + for (const key in this.layerData) { + const layerData = this.layerData[key]; + layerData.programConfiguration.populatePaintArray( + layerData.layer, + layerData.paintVertexArray, this.layoutVertexArray.length, - globalProperties, + this.globalProperties, featureProperties); } } @@ -91,10 +99,10 @@ class ArrayGroup { layoutVertexArray: this.layoutVertexArray.serialize(transferables), elementArray: this.elementArray && this.elementArray.serialize(transferables), elementArray2: this.elementArray2 && this.elementArray2.serialize(transferables), - paintVertexArrays: util.mapObject(this.paintVertexArrays, (array) => { + paintVertexArrays: util.mapObject(this.layerData, (layerData) => { return { - array: array.serialize(transferables), - type: array.constructor.serialize() + array: layerData.paintVertexArray.serialize(transferables), + type: layerData.paintVertexArray.constructor.serialize() }; }), segments: this.segments, diff --git a/js/data/bucket.js b/js/data/bucket.js index edcf49b0f56..30b06d66a96 100644 --- a/js/data/bucket.js +++ b/js/data/bucket.js @@ -2,11 +2,8 @@ const ArrayGroup = require('./array_group'); const BufferGroup = require('./buffer_group'); -const ProgramConfiguration = require('./program_configuration'); const util = require('../util/util'); -const FAKE_ZOOM_HISTORY = { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 }; - /** * The `Bucket` class is the single point of knowledge about turning vector * tiles into WebGL buffers. @@ -26,31 +23,20 @@ class Bucket { * built for this tile. This object facilitates sharing of `Buffer`s be between `Bucket`s. */ - constructor (options) { + constructor (options, programInterface) { this.zoom = options.zoom; this.overscaling = options.overscaling; this.layers = options.layers; this.index = options.index; - this.programConfigurations = util.mapObject(this.programInterfaces, (programInterface) => { - const result = {}; - for (const layer of this.layers) { - result[layer.id] = ProgramConfiguration.createDynamic(programInterface.paintAttributes || [], layer, options); - } - return result; - }); - if (options.arrays) { - this.bufferGroups = util.mapObject(options.arrays, (arrayGroup, programName) => { - return new BufferGroup(arrayGroup, this.programInterfaces[programName]); - }); + this.buffers = new BufferGroup(programInterface, options.layers, options.zoom, options.arrays); + } else { + this.arrays = new ArrayGroup(programInterface, options.layers, options.zoom); } } populate(features, options) { - this.createArrays(); - this.recalculateStyleLayers(); - for (const feature of features) { if (this.layers[0].filter(feature)) { this.addFeature(feature); @@ -59,42 +45,20 @@ class Bucket { } } - createArrays() { - this.arrays = {}; - for (const programName in this.programInterfaces) { - this.arrays[programName] = new ArrayGroup( - this.programInterfaces[programName], - this.programConfigurations[programName]); - } - } - - destroy() { - for (const programName in this.bufferGroups) { - this.bufferGroups[programName].destroy(); - } - } - isEmpty() { - for (const programName in this.arrays) { - if (!this.arrays[programName].isEmpty()) { - return false; - } - } - return true; + return this.arrays.isEmpty(); } serialize(transferables) { return { zoom: this.zoom, layerIds: this.layers.map((l) => l.id), - arrays: util.mapObject(this.arrays, (a) => a.serialize(transferables)) + arrays: this.arrays.serialize(transferables) }; } - recalculateStyleLayers() { - for (const layer of this.layers) { - layer.recalculate(this.zoom, FAKE_ZOOM_HISTORY); - } + destroy() { + this.buffers.destroy(); } } diff --git a/js/data/bucket/circle_bucket.js b/js/data/bucket/circle_bucket.js index eede026f9d8..cac764ca5d4 100644 --- a/js/data/bucket/circle_bucket.js +++ b/js/data/bucket/circle_bucket.js @@ -6,56 +6,54 @@ const ElementArrayType = require('../element_array_type'); const loadGeometry = require('../load_geometry'); const EXTENT = require('../extent'); -const circleInterfaces = { - circle: { - layoutVertexArrayType: new VertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }]), - elementArrayType: new ElementArrayType(), - - paintAttributes: [{ - name: 'a_color', - components: 4, - type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return layer.getPaintValue("circle-color", globalProperties, featureProperties); - }, - multiplier: 255, - paintProperty: 'circle-color' - }, { - name: 'a_radius', - components: 1, - type: 'Uint16', - isLayerConstant: false, - getValue: (layer, globalProperties, featureProperties) => { - return [layer.getPaintValue("circle-radius", globalProperties, featureProperties)]; - }, - multiplier: 10, - paintProperty: 'circle-radius' - }, { - name: 'a_blur', - components: 1, - type: 'Uint16', - isLayerConstant: false, - getValue: (layer, globalProperties, featureProperties) => { - return [layer.getPaintValue("circle-blur", globalProperties, featureProperties)]; - }, - multiplier: 10, - paintProperty: 'circle-blur' - }, { - name: 'a_opacity', - components: 1, - type: 'Uint16', - isLayerConstant: false, - getValue: (layer, globalProperties, featureProperties) => { - return [layer.getPaintValue("circle-opacity", globalProperties, featureProperties)]; - }, - multiplier: 255, - paintProperty: 'circle-opacity' - }] - } +const circleInterface = { + layoutVertexArrayType: new VertexArrayType([{ + name: 'a_pos', + components: 2, + type: 'Int16' + }]), + elementArrayType: new ElementArrayType(), + + paintAttributes: [{ + name: 'a_color', + components: 4, + type: 'Uint8', + getValue: (layer, globalProperties, featureProperties) => { + return layer.getPaintValue("circle-color", globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'circle-color' + }, { + name: 'a_radius', + components: 1, + type: 'Uint16', + isLayerConstant: false, + getValue: (layer, globalProperties, featureProperties) => { + return [layer.getPaintValue("circle-radius", globalProperties, featureProperties)]; + }, + multiplier: 10, + paintProperty: 'circle-radius' + }, { + name: 'a_blur', + components: 1, + type: 'Uint16', + isLayerConstant: false, + getValue: (layer, globalProperties, featureProperties) => { + return [layer.getPaintValue("circle-blur", globalProperties, featureProperties)]; + }, + multiplier: 10, + paintProperty: 'circle-blur' + }, { + name: 'a_opacity', + components: 1, + type: 'Uint16', + isLayerConstant: false, + getValue: (layer, globalProperties, featureProperties) => { + return [layer.getPaintValue("circle-opacity", globalProperties, featureProperties)]; + }, + multiplier: 255, + paintProperty: 'circle-opacity' + }] }; function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) { @@ -72,13 +70,12 @@ function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) { * @private */ class CircleBucket extends Bucket { - - get programInterfaces() { - return circleInterfaces; + constructor(options) { + super(options, circleInterface); } addFeature(feature) { - const arrays = this.arrays.circle; + const arrays = this.arrays; for (const ring of loadGeometry(feature)) { for (const point of ring) { @@ -113,7 +110,7 @@ class CircleBucket extends Bucket { } } - arrays.populatePaintArrays(this.layers, {zoom: this.zoom}, feature.properties); + arrays.populatePaintArrays(feature.properties); } } diff --git a/js/data/bucket/fill_bucket.js b/js/data/bucket/fill_bucket.js index bdd659af94e..e31c9555947 100644 --- a/js/data/bucket/fill_bucket.js +++ b/js/data/bucket/fill_bucket.js @@ -9,54 +9,52 @@ const classifyRings = require('../../util/classify_rings'); const assert = require('assert'); const EARCUT_MAX_RINGS = 500; -const fillInterfaces = { - fill: { - layoutVertexArrayType: new VertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }]), - elementArrayType: new ElementArrayType(3), - elementArrayType2: new ElementArrayType(2), - - paintAttributes: [{ - name: 'a_color', - components: 4, - type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return layer.getPaintValue("fill-color", globalProperties, featureProperties); - }, - multiplier: 255, - paintProperty: 'fill-color' - }, { - name: 'a_outline_color', - components: 4, - type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return layer.getPaintValue("fill-outline-color", globalProperties, featureProperties); - }, - multiplier: 255, - paintProperty: 'fill-outline-color' - }, { - name: 'a_opacity', - components: 1, - type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return [layer.getPaintValue("fill-opacity", globalProperties, featureProperties)]; - }, - multiplier: 255, - paintProperty: 'fill-opacity' - }] - } +const fillInterface = { + layoutVertexArrayType: new VertexArrayType([{ + name: 'a_pos', + components: 2, + type: 'Int16' + }]), + elementArrayType: new ElementArrayType(3), + elementArrayType2: new ElementArrayType(2), + + paintAttributes: [{ + name: 'a_color', + components: 4, + type: 'Uint8', + getValue: (layer, globalProperties, featureProperties) => { + return layer.getPaintValue("fill-color", globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'fill-color' + }, { + name: 'a_outline_color', + components: 4, + type: 'Uint8', + getValue: (layer, globalProperties, featureProperties) => { + return layer.getPaintValue("fill-outline-color", globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'fill-outline-color' + }, { + name: 'a_opacity', + components: 1, + type: 'Uint8', + getValue: (layer, globalProperties, featureProperties) => { + return [layer.getPaintValue("fill-opacity", globalProperties, featureProperties)]; + }, + multiplier: 255, + paintProperty: 'fill-opacity' + }] }; class FillBucket extends Bucket { - get programInterfaces() { - return fillInterfaces; + constructor(options) { + super(options, fillInterface); } addFeature(feature) { - const arrays = this.arrays.fill; + const arrays = this.arrays; for (const polygon of classifyRings(loadGeometry(feature), EARCUT_MAX_RINGS)) { let numVertices = 0; @@ -112,7 +110,7 @@ class FillBucket extends Bucket { triangleSegment.primitiveLength += indices.length / 3; } - arrays.populatePaintArrays(this.layers, {zoom: this.zoom}, feature.properties); + arrays.populatePaintArrays(feature.properties); } } diff --git a/js/data/bucket/fill_extrusion_bucket.js b/js/data/bucket/fill_extrusion_bucket.js index a625fdbdbfb..dd5e533e2fe 100644 --- a/js/data/bucket/fill_extrusion_bucket.js +++ b/js/data/bucket/fill_extrusion_bucket.js @@ -10,54 +10,52 @@ const classifyRings = require('../../util/classify_rings'); const assert = require('assert'); const EARCUT_MAX_RINGS = 500; -const fillExtrusionInterfaces = { - fillextrusion: { - layoutVertexArrayType: new VertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }, { - name: 'a_normal', - components: 3, - type: 'Int16' - }, { - name: 'a_edgedistance', - components: 1, - type: 'Int16' - }]), - elementArrayType: new ElementArrayType(3), - - paintAttributes: [{ - name: 'a_minH', - components: 1, - type: 'Uint16', - getValue: (layer, globalProperties, featureProperties) => { - return [Math.max(layer.getPaintValue("fill-extrude-base", globalProperties, featureProperties), 0)]; - }, - multiplier: 1, - paintProperty: 'fill-extrude-base' - }, { - name: 'a_maxH', - components: 1, - type: 'Uint16', - getValue: (layer, globalProperties, featureProperties) => { - return [Math.max(layer.getPaintValue("fill-extrude-height", globalProperties, featureProperties), 0)]; - }, - multiplier: 1, - paintProperty: 'fill-extrude-height' - }, { - name: 'a_color', - components: 4, - type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - const color = layer.getPaintValue("fill-color", globalProperties, featureProperties); - color[3] = 1.0; - return color; - }, - multiplier: 255, - paintProperty: 'fill-color' - }] - } +const fillExtrusionInterface = { + layoutVertexArrayType: new VertexArrayType([{ + name: 'a_pos', + components: 2, + type: 'Int16' + }, { + name: 'a_normal', + components: 3, + type: 'Int16' + }, { + name: 'a_edgedistance', + components: 1, + type: 'Int16' + }]), + elementArrayType: new ElementArrayType(3), + + paintAttributes: [{ + name: 'a_minH', + components: 1, + type: 'Uint16', + getValue: (layer, globalProperties, featureProperties) => { + return [Math.max(layer.getPaintValue("fill-extrude-base", globalProperties, featureProperties), 0)]; + }, + multiplier: 1, + paintProperty: 'fill-extrude-base' + }, { + name: 'a_maxH', + components: 1, + type: 'Uint16', + getValue: (layer, globalProperties, featureProperties) => { + return [Math.max(layer.getPaintValue("fill-extrude-height", globalProperties, featureProperties), 0)]; + }, + multiplier: 1, + paintProperty: 'fill-extrude-height' + }, { + name: 'a_color', + components: 4, + type: 'Uint8', + getValue: (layer, globalProperties, featureProperties) => { + const color = layer.getPaintValue("fill-color", globalProperties, featureProperties); + color[3] = 1.0; + return color; + }, + multiplier: 255, + paintProperty: 'fill-color' + }] }; const FACTOR = Math.pow(2, 13); @@ -78,12 +76,12 @@ function addVertex(vertexArray, x, y, nx, ny, nz, t, e) { } class FillExtrusionBucket extends Bucket { - get programInterfaces() { - return fillExtrusionInterfaces; + constructor(options) { + super(options, fillExtrusionInterface); } addFeature(feature) { - const arrays = this.arrays.fillextrusion; + const arrays = this.arrays; for (const polygon of classifyRings(loadGeometry(feature), EARCUT_MAX_RINGS)) { let numVertices = 0; @@ -157,7 +155,7 @@ class FillExtrusionBucket extends Bucket { segment.primitiveLength += triangleIndices.length / 3; } - arrays.populatePaintArrays(this.layers, {zoom: this.zoom}, feature.properties); + arrays.populatePaintArrays(feature.properties); } } diff --git a/js/data/bucket/line_bucket.js b/js/data/bucket/line_bucket.js index 6110be955a7..bad53c3d70f 100644 --- a/js/data/bucket/line_bucket.js +++ b/js/data/bucket/line_bucket.js @@ -39,29 +39,27 @@ const LINE_DISTANCE_SCALE = 1 / 2; // The maximum line distance, in tile units, that fits in the buffer. const MAX_LINE_DISTANCE = Math.pow(2, LINE_DISTANCE_BUFFER_BITS - 1) / LINE_DISTANCE_SCALE; -const lineInterfaces = { - line: { - layoutVertexArrayType: new VertexArrayType([{ - name: 'a_pos', - components: 2, - type: 'Int16' - }, { - name: 'a_data', - components: 4, - type: 'Uint8' - }]), - paintAttributes: [{ - name: 'a_color', - components: 4, - type: 'Uint8', - getValue: (layer, globalProperties, featureProperties) => { - return layer.getPaintValue("line-color", globalProperties, featureProperties); - }, - multiplier: 255, - paintProperty: 'line-color' - }], - elementArrayType: new ElementArrayType() - } +const lineInterface = { + layoutVertexArrayType: new VertexArrayType([{ + name: 'a_pos', + components: 2, + type: 'Int16' + }, { + name: 'a_data', + components: 4, + type: 'Uint8' + }]), + paintAttributes: [{ + name: 'a_color', + components: 4, + type: 'Uint8', + getValue: (layer, globalProperties, featureProperties) => { + return layer.getPaintValue("line-color", globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'line-color' + }], + elementArrayType: new ElementArrayType() }; function addLineVertex(layoutVertexBuffer, point, extrude, tx, ty, dir, linesofar) { @@ -86,9 +84,8 @@ function addLineVertex(layoutVertexBuffer, point, extrude, tx, ty, dir, linesofa * @private */ class LineBucket extends Bucket { - - get programInterfaces() { - return lineInterfaces; + constructor(options) { + super(options, lineInterface); } addFeature(feature) { @@ -122,7 +119,7 @@ class LineBucket extends Bucket { lastVertex = vertices[len - 1], closed = firstVertex.equals(lastVertex); - const arrays = this.arrays.line; + const arrays = this.arrays; // we could be more precise, but it would only save a negligible amount of space const segment = arrays.prepareSegment('line', len * 10); @@ -356,7 +353,7 @@ class LineBucket extends Bucket { startOfLine = false; } - arrays.populatePaintArrays(this.layers, {zoom: this.zoom}, featureProperties); + arrays.populatePaintArrays(featureProperties); } /** @@ -372,7 +369,7 @@ class LineBucket extends Bucket { addCurrentVertex(currentVertex, distance, normal, endLeft, endRight, round, segment) { const tx = round ? 1 : 0; let extrude; - const arrays = this.arrays.line; + const arrays = this.arrays; const layoutVertexArray = arrays.layoutVertexArray; const elementArray = arrays.elementArray; @@ -421,7 +418,7 @@ class LineBucket extends Bucket { addPieSliceVertex(currentVertex, distance, extrude, lineTurnsLeft, segment) { const ty = lineTurnsLeft ? 1 : 0; extrude = extrude.mult(lineTurnsLeft ? -1 : 1); - const arrays = this.arrays.line; + const arrays = this.arrays; const layoutVertexArray = arrays.layoutVertexArray; const elementArray = arrays.elementArray; diff --git a/js/data/bucket/symbol_bucket.js b/js/data/bucket/symbol_bucket.js index e2d985b09cd..3c99c2987ff 100644 --- a/js/data/bucket/symbol_bucket.js +++ b/js/data/bucket/symbol_bucket.js @@ -1,8 +1,8 @@ 'use strict'; const Point = require('point-geometry'); - -const Bucket = require('../bucket'); +const ArrayGroup = require('../array_group'); +const BufferGroup = require('../buffer_group'); const VertexArrayType = require('../vertex_array_type'); const ElementArrayType = require('../element_array_type'); const EXTENT = require('../extent'); @@ -105,40 +105,30 @@ function addCollisionBoxVertex(layoutVertexArray, point, extrude, maxZoom, place placementZoom * 10); } -class SymbolBucket extends Bucket { +class SymbolBucket { constructor(options) { - super(options); - this.collisionBoxArray = options.collisionBoxArray; this.symbolQuadsArray = options.symbolQuadsArray; this.symbolInstancesArray = options.symbolInstancesArray; + this.zoom = options.zoom; + this.overscaling = options.overscaling; + this.layers = options.layers; this.sdfIcons = options.sdfIcons; this.iconsNeedLinear = options.iconsNeedLinear; this.adjustedTextSize = options.adjustedTextSize; this.adjustedIconSize = options.adjustedIconSize; this.fontstack = options.fontstack; - this.layer = this.layers[0]; - } - - get programInterfaces() { - return symbolInterfaces; - } - serialize() { - const serialized = Bucket.prototype.serialize.apply(this); - serialized.sdfIcons = this.sdfIcons; - serialized.iconsNeedLinear = this.iconsNeedLinear; - serialized.adjustedTextSize = this.adjustedTextSize; - serialized.adjustedIconSize = this.adjustedIconSize; - serialized.fontstack = this.fontstack; - return serialized; + if (options.arrays) { + this.buffers = util.mapObject(options.arrays, (arrays, key) => { + return new BufferGroup(symbolInterfaces[key], options.layers, options.zoom, options.arrays[key]); + }); + } } populate(features, options) { - this.recalculateStyleLayers(); - - const layout = this.layer.layout; + const layout = this.layers[0].layout; const textField = layout['text-field']; const textFont = layout['text-font']; const iconImage = layout['icon-image']; @@ -157,7 +147,7 @@ class SymbolBucket extends Bucket { const stack = stacks[textFont] = stacks[textFont] || {}; for (const feature of features) { - if (!this.layer.filter(feature)) { + if (!this.layers[0].filter(feature)) { continue; } @@ -202,16 +192,49 @@ class SymbolBucket extends Bucket { } } + isEmpty() { + return this.arrays.icon.isEmpty() && + this.arrays.glyph.isEmpty() && + this.arrays.collisionBox.isEmpty(); + } + + serialize(transferables) { + return { + zoom: this.zoom, + layerIds: this.layers.map((l) => l.id), + sdfIcons: this.sdfIcons, + iconsNeedLinear: this.iconsNeedLinear, + adjustedTextSize: this.adjustedTextSize, + adjustedIconSize: this.adjustedIconSize, + fontstack: this.fontstack, + arrays: util.mapObject(this.arrays, (a) => a.serialize(transferables)) + }; + } + + destroy() { + this.buffers.icon.destroy(); + this.buffers.glyph.destroy(); + this.buffers.collisionBox.destroy(); + } + + createArrays() { + this.arrays = util.mapObject(symbolInterfaces, (programInterface) => { + return new ArrayGroup(programInterface, this.layers, this.zoom); + }); + } + prepare(stacks, icons) { + this.createArrays(); + // To reduce the number of labels that jump around when zooming we need // to use a text-size value that is the same for all zoom levels. // This calculates text-size at a high zoom level so that all tiles can // use the same value when calculating anchor positions. const zoomHistory = { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 }; - this.adjustedTextMaxSize = this.layer.getLayoutValue('text-size', {zoom: 18, zoomHistory: zoomHistory}); - this.adjustedTextSize = this.layer.getLayoutValue('text-size', {zoom: this.zoom + 1, zoomHistory: zoomHistory}); - this.adjustedIconMaxSize = this.layer.getLayoutValue('icon-size', {zoom: 18, zoomHistory: zoomHistory}); - this.adjustedIconSize = this.layer.getLayoutValue('icon-size', {zoom: this.zoom + 1, zoomHistory: zoomHistory}); + this.adjustedTextMaxSize = this.layers[0].getLayoutValue('text-size', {zoom: 18, zoomHistory: zoomHistory}); + this.adjustedTextSize = this.layers[0].getLayoutValue('text-size', {zoom: this.zoom + 1, zoomHistory: zoomHistory}); + this.adjustedIconMaxSize = this.layers[0].getLayoutValue('icon-size', {zoom: 18, zoomHistory: zoomHistory}); + this.adjustedIconSize = this.layers[0].getLayoutValue('icon-size', {zoom: this.zoom + 1, zoomHistory: zoomHistory}); const tileSize = 512 * this.overscaling; this.tilePixelRatio = EXTENT / tileSize; @@ -219,7 +242,7 @@ class SymbolBucket extends Bucket { this.iconsNeedLinear = false; this.symbolInstancesStartIndex = this.symbolInstancesArray.length; - const layout = this.layer.layout; + const layout = this.layers[0].layout; let horizontalAlign = 0.5, verticalAlign = 0.5; @@ -281,7 +304,7 @@ class SymbolBucket extends Bucket { } if (image.pixelRatio !== 1) { this.iconsNeedLinear = true; - } else if (layout['icon-rotate'] !== 0 || !this.layer.isLayoutValueFeatureConstant('icon-rotate')) { + } else if (layout['icon-rotate'] !== 0 || !this.layers[0].isLayoutValueFeatureConstant('icon-rotate')) { this.iconsNeedLinear = true; } } @@ -296,7 +319,7 @@ class SymbolBucket extends Bucket { addFeature(feature, shapedText, shapedIcon) { const lines = feature.geometry; - const layout = this.layer.layout; + const layout = this.layers[0].layout; const glyphSize = 24; @@ -378,7 +401,7 @@ class SymbolBucket extends Bucket { // be drawn across tile boundaries. Instead they need to be included in // the buffers for both tiles and clipped to tile boundaries at draw time. const addToBuffers = inside || mayOverlap; - this.addSymbolInstance(anchor, line, shapedText, shapedIcon, this.layer, + this.addSymbolInstance(anchor, line, shapedText, shapedIcon, this.layers[0], addToBuffers, this.symbolInstancesArray.length, this.collisionBoxArray, feature.index, feature.sourceLayerIndex, this.index, textBoxScale, textPadding, textAlongLine, iconBoxScale, iconPadding, iconAlongLine, {zoom: this.zoom}, feature.properties); @@ -422,14 +445,12 @@ class SymbolBucket extends Bucket { } place(collisionTile, showCollisionBoxes) { - this.recalculateStyleLayers(); - // Calculate which labels can be shown and when they can be shown and // create the bufers used for rendering. this.createArrays(); - const layout = this.layer.layout; + const layout = this.layers[0].layout; const maxScale = collisionTile.maxScale; @@ -507,14 +528,14 @@ class SymbolBucket extends Bucket { if (hasText) { collisionTile.insertCollisionFeature(textCollisionFeature, glyphScale, layout['text-ignore-placement']); if (glyphScale <= maxScale) { - this.addSymbols('glyph', symbolInstance.glyphQuadStartIndex, symbolInstance.glyphQuadEndIndex, glyphScale, layout['text-keep-upright'], textAlongLine, collisionTile.angle); + this.addSymbols(this.arrays.glyph, symbolInstance.glyphQuadStartIndex, symbolInstance.glyphQuadEndIndex, glyphScale, layout['text-keep-upright'], textAlongLine, collisionTile.angle); } } if (hasIcon) { collisionTile.insertCollisionFeature(iconCollisionFeature, iconScale, layout['icon-ignore-placement']); if (iconScale <= maxScale) { - this.addSymbols('icon', symbolInstance.iconQuadStartIndex, symbolInstance.iconQuadEndIndex, iconScale, layout['icon-keep-upright'], iconAlongLine, collisionTile.angle); + this.addSymbols(this.arrays.icon, symbolInstance.iconQuadStartIndex, symbolInstance.iconQuadEndIndex, iconScale, layout['icon-keep-upright'], iconAlongLine, collisionTile.angle); } } @@ -523,8 +544,7 @@ class SymbolBucket extends Bucket { if (showCollisionBoxes) this.addToDebugBuffers(collisionTile); } - addSymbols(programName, quadsStart, quadsEnd, scale, keepUpright, alongLine, placementAngle) { - const arrays = this.arrays[programName]; + addSymbols(arrays, quadsStart, quadsEnd, scale, keepUpright, alongLine, placementAngle) { const elementArray = arrays.elementArray; const layoutVertexArray = arrays.layoutVertexArray; diff --git a/js/data/buffer_group.js b/js/data/buffer_group.js index b8cb2a67b94..d1ba1e12508 100644 --- a/js/data/buffer_group.js +++ b/js/data/buffer_group.js @@ -2,34 +2,40 @@ const util = require('../util/util'); const Buffer = require('./buffer'); +const ProgramConfiguration = require('./program_configuration'); const VertexArrayObject = require('../render/vertex_array_object'); class BufferGroup { - - constructor(arrayGroup, programInterface) { - this.layoutVertexBuffer = new Buffer(arrayGroup.layoutVertexArray, + constructor(programInterface, layers, zoom, arrays) { + this.layoutVertexBuffer = new Buffer(arrays.layoutVertexArray, programInterface.layoutVertexArrayType.serialize(), Buffer.BufferType.VERTEX); - if (arrayGroup.elementArray) { - this.elementBuffer = new Buffer(arrayGroup.elementArray, + if (arrays.elementArray) { + this.elementBuffer = new Buffer(arrays.elementArray, programInterface.elementArrayType.serialize(), Buffer.BufferType.ELEMENT); } - if (arrayGroup.elementArray2) { - this.elementBuffer2 = new Buffer(arrayGroup.elementArray2, + if (arrays.elementArray2) { + this.elementBuffer2 = new Buffer(arrays.elementArray2, programInterface.elementArrayType2.serialize(), Buffer.BufferType.ELEMENT); } - this.paintVertexBuffers = util.mapObject(arrayGroup.paintVertexArrays, (array) => { - return new Buffer(array.array, array.type, Buffer.BufferType.VERTEX); - }); + this.layerData = {}; + for (const layer of layers) { + const array = arrays.paintVertexArrays[layer.id]; + this.layerData[layer.id] = { + programConfiguration: ProgramConfiguration.createDynamic( + programInterface.paintAttributes || [], layer, zoom), + paintVertexBuffer: new Buffer(array.array, array.type, Buffer.BufferType.VERTEX) + }; + } - this.segments = arrayGroup.segments; - this.segments2 = arrayGroup.segments2; + this.segments = arrays.segments; + this.segments2 = arrays.segments2; for (const segments of [this.segments, this.segments2]) { for (const segment of segments || []) { - segment.vaos = util.mapObject(arrayGroup.paintVertexArrays, () => { + segment.vaos = util.mapObject(arrays.paintVertexArrays, () => { return new VertexArrayObject(); }); } @@ -44,8 +50,8 @@ class BufferGroup { if (this.elementBuffer2) { this.elementBuffer2.destroy(); } - for (const n in this.paintVertexBuffers) { - this.paintVertexBuffers[n].destroy(); + for (const n in this.layerData) { + this.layerData[n].paintVertexBuffer.destroy(); } for (const segments of [this.segments, this.segments2]) { for (const segment of segments || []) { diff --git a/js/data/program_configuration.js b/js/data/program_configuration.js index 01fc77e95ba..53caf292968 100644 --- a/js/data/program_configuration.js +++ b/js/data/program_configuration.js @@ -22,7 +22,7 @@ const assert = require('assert'); * @private */ class ProgramConfiguration { - static createDynamic(attributes, layer, options) { + static createDynamic(attributes, layer, zoom) { const self = new ProgramConfiguration(); self.attributes = []; @@ -61,7 +61,7 @@ class ProgramConfiguration { // Find the four closest stops, ideally with two on each side of the zoom level. let numStops = 0; const zoomLevels = layer.getPaintValueStopZoomLevels(attribute.paintProperty); - while (numStops < zoomLevels.length && zoomLevels[numStops] < options.zoom) numStops++; + while (numStops < zoomLevels.length && zoomLevels[numStops] < zoom) numStops++; const stopOffset = Math.max(0, Math.min(zoomLevels.length - 4, numStops - 2)); const fourZoomLevels = []; diff --git a/js/render/draw_circle.js b/js/render/draw_circle.js index 10857014d42..e3960376ccb 100644 --- a/js/render/draw_circle.js +++ b/js/render/draw_circle.js @@ -23,8 +23,9 @@ function drawCircles(painter, sourceCache, layer, coords) { const bucket = tile.getBucket(layer); if (!bucket) continue; - const buffers = bucket.bufferGroups.circle; - const programConfiguration = bucket.programConfigurations.circle[layer.id]; + const buffers = bucket.buffers; + const layerData = buffers.layerData[layer.id]; + const programConfiguration = layerData.programConfiguration; const program = painter.useProgram('circle', programConfiguration); programConfiguration.setUniforms(gl, program, layer, {zoom: painter.transform.zoom}); @@ -48,7 +49,7 @@ function drawCircles(painter, sourceCache, layer, coords) { )); for (const segment of buffers.segments) { - segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, buffers.paintVertexBuffers[layer.id], segment.vertexOffset); + segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, layerData.paintVertexBuffer, segment.vertexOffset); gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2); } } diff --git a/js/render/draw_collision_debug.js b/js/render/draw_collision_debug.js index 1cd363d6939..cb5b174ab43 100644 --- a/js/render/draw_collision_debug.js +++ b/js/render/draw_collision_debug.js @@ -22,7 +22,7 @@ function drawCollisionDebug(painter, sourceCache, layer, coords) { gl.uniform1f(program.u_zoom, painter.transform.zoom * 10); gl.uniform1f(program.u_maxzoom, (tile.coord.z + 1) * 10); - const buffers = bucket.bufferGroups.collisionBox; + const buffers = bucket.buffers.collisionBox; for (const segment of buffers.segments) { segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, null, segment.vertexOffset); gl.drawElements(gl.LINES, segment.primitiveLength * 2, gl.UNSIGNED_SHORT, segment.primitiveOffset * 2 * 2); diff --git a/js/render/draw_extrusion.js b/js/render/draw_extrusion.js index f7bc7da196f..3617642e9d4 100644 --- a/js/render/draw_extrusion.js +++ b/js/render/draw_extrusion.js @@ -148,12 +148,13 @@ function drawExtrusion(painter, source, layer, coord) { const bucket = tile.getBucket(layer); if (!bucket) return; - const buffers = bucket.bufferGroups.fillextrusion; + const buffers = bucket.buffers; const gl = painter.gl; const image = layer.paint['fill-pattern']; - const programConfiguration = bucket.programConfigurations.fillextrusion[layer.id]; + const layerData = buffers.layerData[layer.id]; + const programConfiguration = layerData.programConfiguration; const program = painter.useProgram(image ? 'fillExtrudePattern' : 'fillExtrude', programConfiguration); programConfiguration.setUniforms(gl, program, layer, {zoom: painter.transform.zoom}); @@ -165,7 +166,7 @@ function drawExtrusion(painter, source, layer, coord) { setLight(program, painter); for (const segment of buffers.segments) { - segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, buffers.paintVertexBuffers[layer.id], segment.vertexOffset); + segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, layerData.paintVertexBuffer, segment.vertexOffset); gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2); } } diff --git a/js/render/draw_fill.js b/js/render/draw_fill.js index 9cc4288c2c5..640c95626b5 100644 --- a/js/render/draw_fill.js +++ b/js/render/draw_fill.js @@ -51,15 +51,16 @@ function drawFill(painter, sourceCache, layer, coord) { const bucket = tile.getBucket(layer); if (!bucket) return; - const buffers = bucket.bufferGroups.fill; + const buffers = bucket.buffers; const gl = painter.gl; const image = layer.paint['fill-pattern']; + const layerData = buffers.layerData[layer.id]; + let program; if (!image) { - - const programConfiguration = bucket.programConfigurations.fill[layer.id]; + const programConfiguration = layerData.programConfiguration; program = painter.useProgram('fill', programConfiguration); programConfiguration.setUniforms(gl, program, layer, {zoom: painter.transform.zoom}); @@ -83,7 +84,7 @@ function drawFill(painter, sourceCache, layer, coord) { painter.enableTileClippingMask(coord); for (const segment of buffers.segments) { - segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, buffers.paintVertexBuffers[layer.id], segment.vertexOffset); + segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, layerData.paintVertexBuffer, segment.vertexOffset); gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2); } } @@ -93,7 +94,8 @@ function drawStroke(painter, sourceCache, layer, coord) { const bucket = tile.getBucket(layer); if (!bucket) return; - const buffers = bucket.bufferGroups.fill; + const buffers = bucket.buffers; + const layerData = buffers.layerData[layer.id]; const gl = painter.gl; const image = layer.paint['fill-pattern']; @@ -105,7 +107,7 @@ function drawStroke(painter, sourceCache, layer, coord) { gl.uniform2f(program.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight); } else { - const programConfiguration = bucket.programConfigurations.fill[layer.id]; + const programConfiguration = layerData.programConfiguration; program = painter.useProgram('fillOutline', programConfiguration); programConfiguration.setUniforms(gl, program, layer, {zoom: painter.transform.zoom}); gl.uniform2f(program.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight); @@ -127,7 +129,7 @@ function drawStroke(painter, sourceCache, layer, coord) { painter.enableTileClippingMask(coord); for (const segment of buffers.segments2) { - segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer2, buffers.paintVertexBuffers[layer.id], segment.vertexOffset); + segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer2, layerData.paintVertexBuffer, segment.vertexOffset); gl.drawElements(gl.LINES, segment.primitiveLength * 2, gl.UNSIGNED_SHORT, segment.primitiveOffset * 2 * 2); } } diff --git a/js/render/draw_line.js b/js/render/draw_line.js index f8df4c23bc2..7ece8c88f2d 100644 --- a/js/render/draw_line.js +++ b/js/render/draw_line.js @@ -34,13 +34,14 @@ function drawLineTile(painter, sourceCache, layer, coord) { const bucket = tile.getBucket(layer); if (!bucket) return; - const buffers = bucket.bufferGroups.line; + const buffers = bucket.buffers; + const layerData = buffers.layerData[layer.id]; const gl = painter.gl; const dasharray = layer.paint['line-dasharray']; const image = layer.paint['line-pattern']; - const programConfiguration = bucket.programConfigurations.line[layer.id]; + const programConfiguration = layerData.programConfiguration; const program = painter.useProgram(dasharray ? 'lineSDF' : image ? 'linePattern' : 'line', programConfiguration); programConfiguration.setUniforms(gl, program, layer, {zoom: painter.transform.zoom}); @@ -121,7 +122,7 @@ function drawLineTile(painter, sourceCache, layer, coord) { gl.uniform1f(program.u_ratio, 1 / pixelsToTileUnits(tile, 1, painter.transform.zoom)); for (const segment of buffers.segments) { - segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, buffers.paintVertexBuffers[layer.id], segment.vertexOffset); + segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, layerData.paintVertexBuffer, segment.vertexOffset); gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2); } } diff --git a/js/render/draw_symbol.js b/js/render/draw_symbol.js index 14c15cfd9db..580637d03e4 100644 --- a/js/render/draw_symbol.js +++ b/js/render/draw_symbol.js @@ -84,7 +84,7 @@ function drawLayerSymbols(painter, sourceCache, layer, coords, isText, const tile = sourceCache.getTile(coords[j]); const bucket = tile.getBucket(layer); if (!bucket) continue; - const buffers = isText ? bucket.bufferGroups.glyph : bucket.bufferGroups.icon; + const buffers = isText ? bucket.buffers.glyph : bucket.buffers.icon; if (!buffers.segments.length) continue; painter.enableTileClippingMask(coords[j]); diff --git a/js/source/worker_tile.js b/js/source/worker_tile.js index 7fbe4bbfea3..13e405fc620 100644 --- a/js/source/worker_tile.js +++ b/js/source/worker_tile.js @@ -9,6 +9,8 @@ const SymbolInstancesArray = require('../symbol/symbol_instances'); const SymbolQuadsArray = require('../symbol/symbol_quads'); const assert = require('assert'); +const FAKE_ZOOM_HISTORY = { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 }; + class WorkerTile { constructor(params) { this.coord = params.coord; @@ -82,8 +84,12 @@ class WorkerTile { if (layer.maxzoom && this.zoom >= layer.maxzoom) continue; if (layer.layout && layer.layout.visibility === 'none') continue; + for (const layer of family) { + layer.recalculate(this.zoom, FAKE_ZOOM_HISTORY); + } + const bucket = buckets[layer.id] = layer.createBucket({ - index: bucketIndex++, + index: bucketIndex, layers: family, zoom: this.zoom, overscaling: this.overscaling, @@ -93,7 +99,9 @@ class WorkerTile { }); bucket.populate(features, options); - featureIndex.bucketLayerIDs[bucket.index] = family.map((l) => l.id); + featureIndex.bucketLayerIDs[bucketIndex] = family.map((l) => l.id); + + bucketIndex++; } } @@ -139,6 +147,11 @@ class WorkerTile { deps++; if (deps === 2) { for (const bucket of this.symbolBuckets) { + // Layers are shared and may have been used by a WorkerTile with a different zoom. + for (const layer of bucket.layers) { + layer.recalculate(this.zoom, FAKE_ZOOM_HISTORY); + } + bucket.prepare(stacks, icons); bucket.place(collisionTile, this.showCollisionBoxes); } @@ -173,7 +186,13 @@ class WorkerTile { } const collisionTile = new CollisionTile(angle, pitch, this.collisionBoxArray); + for (const bucket of this.symbolBuckets) { + // Layers are shared and may have been used by a WorkerTile with a different zoom. + for (const layer of bucket.layers) { + layer.recalculate(this.zoom, FAKE_ZOOM_HISTORY); + } + bucket.place(collisionTile, showCollisionBoxes); } diff --git a/test/js/data/bucket.test.js b/test/js/data/bucket.test.js index 4325b6d08a7..08776bd177f 100644 --- a/test/js/data/bucket.test.js +++ b/test/js/data/bucket.test.js @@ -33,37 +33,37 @@ test('Bucket', (t) => { function create(options) { options = options || {}; + const programInterface = { + layoutVertexArrayType: new VertexArrayType(options.layoutAttributes || [{ + name: 'a_box', + components: 2, + type: 'Int16' + }]), + elementArrayType: new ElementArrayType(), + elementArrayType2: new ElementArrayType(2), + + paintAttributes: options.paintAttributes || [{ + name: 'a_map', + type: 'Int16', + getValue: function(layer, globalProperties, featureProperties) { + return [featureProperties.x]; + }, + paintProperty: 'circle-color' + }] + }; + class Class extends Bucket { - get programInterfaces() { - return { - test: { - layoutVertexArrayType: new VertexArrayType(options.layoutAttributes || [{ - name: 'a_box', - components: 2, - type: 'Int16' - }]), - elementArrayType: new ElementArrayType(), - elementArrayType2: new ElementArrayType(2), - - paintAttributes: options.paintAttributes || [{ - name: 'a_map', - type: 'Int16', - getValue: function(layer, globalProperties, featureProperties) { - return [featureProperties.x]; - }, - paintProperty: 'circle-color' - }] - } - }; + constructor(options) { + super(options, programInterface); } addFeature(feature) { - const arrays = this.arrays.test; + const arrays = this.arrays; const point = feature.loadGeometry()[0][0]; arrays.layoutVertexArray.emplaceBack(point.x * 2, point.y * 2); arrays.elementArray.emplaceBack(1, 2, 3); arrays.elementArray2.emplaceBack(point.x, point.y); - arrays.populatePaintArrays(this.layers, {}, feature.properties); + arrays.populatePaintArrays(feature.properties); } } @@ -91,24 +91,24 @@ test('Bucket', (t) => { bucket.populate([createFeature(17, 42)], createOptions()); - const testVertex = bucket.arrays.test.layoutVertexArray; + const testVertex = bucket.arrays.layoutVertexArray; t.equal(testVertex.length, 1); const v0 = testVertex.get(0); t.equal(v0.a_box0, 34); t.equal(v0.a_box1, 84); - const paintVertex = bucket.arrays.test.paintVertexArrays.layerid; + const paintVertex = bucket.arrays.layerData.layerid.paintVertexArray; t.equal(paintVertex.length, 1); const p0 = paintVertex.get(0); t.equal(p0.a_map, 17); - const testElement = bucket.arrays.test.elementArray; + const testElement = bucket.arrays.elementArray; t.equal(testElement.length, 1); const e1 = testElement.get(0); t.equal(e1.vertices0, 1); t.equal(e1.vertices1, 2); t.equal(e1.vertices2, 3); - const testElement2 = bucket.arrays.test.elementArray2; + const testElement2 = bucket.arrays.elementArray2; t.equal(testElement2.length, 1); const e2 = testElement2.get(0); t.equal(e2.vertices0, 17); @@ -125,9 +125,9 @@ test('Bucket', (t) => { bucket.populate([createFeature(17, 42)], createOptions()); - const v0 = bucket.arrays.test.layoutVertexArray.get(0); - const a0 = bucket.arrays.test.paintVertexArrays.one.get(0); - const b0 = bucket.arrays.test.paintVertexArrays.two.get(0); + const v0 = bucket.arrays.layoutVertexArray.get(0); + const a0 = bucket.arrays.layerData.one.paintVertexArray.get(0); + const b0 = bucket.arrays.layerData.two.paintVertexArray.get(0); t.equal(a0.a_map, 17); t.equal(b0.a_map, 17); t.equal(v0.a_box0, 34); @@ -152,9 +152,9 @@ test('Bucket', (t) => { bucket.populate([createFeature(17, 42)], createOptions()); - t.equal(bucket.arrays.test.layoutVertexArray.bytesPerElement, 0); + t.equal(bucket.arrays.layoutVertexArray.bytesPerElement, 0); t.deepEqual( - bucket.programConfigurations.test.one.uniforms[0].getValue.call(bucket), + bucket.arrays.layerData.one.programConfiguration.uniforms[0].getValue.call(bucket), [5] ); @@ -172,31 +172,16 @@ test('Bucket', (t) => { bucket.populate([createFeature(17, 42)], createOptions()); - const v0 = bucket.arrays.test.layoutVertexArray.get(0); + const v0 = bucket.arrays.layoutVertexArray.get(0); t.equal(v0.a_map, 34); t.end(); }); - t.test('reset buffers', (t) => { - const bucket = create(); - - bucket.populate([createFeature(17, 42)], createOptions()); - - t.notEqual(bucket.arrays.test.layoutVertexArray.length, 0); - bucket.createArrays(); - t.equal(bucket.arrays.test.layoutVertexArray.length, 0); - - t.end(); - }); - t.test('isEmpty', (t) => { const bucket = create(); t.ok(bucket.isEmpty()); - bucket.createArrays(); - t.ok(bucket.isEmpty()); - bucket.populate([createFeature(17, 42)], createOptions()); t.ok(!bucket.isEmpty()); @@ -211,43 +196,10 @@ test('Bucket', (t) => { bucket.serialize(transferables); t.equal(4, transferables.length); - t.equal(bucket.arrays.test.layoutVertexArray.arrayBuffer, transferables[0]); - t.equal(bucket.arrays.test.elementArray.arrayBuffer, transferables[1]); - t.equal(bucket.arrays.test.elementArray2.arrayBuffer, transferables[2]); - t.equal(bucket.arrays.test.paintVertexArrays.layerid.arrayBuffer, transferables[3]); - - t.end(); - }); - - t.test('add features after resetting buffers', (t) => { - const bucket = create(); - - bucket.populate([createFeature(1, 5)], createOptions()); - bucket.createArrays(); - bucket.populate([createFeature(17, 42)], createOptions()); - - const testVertex = bucket.arrays.test.layoutVertexArray; - t.equal(testVertex.length, 1); - const v0 = testVertex.get(0); - t.equal(v0.a_box0, 34); - t.equal(v0.a_box1, 84); - const testPaintVertex = bucket.arrays.test.paintVertexArrays.layerid; - t.equal(testPaintVertex.length, 1); - const p0 = testPaintVertex.get(0); - t.equal(p0.a_map, 17); - - const testElement = bucket.arrays.test.elementArray; - t.equal(testElement.length, 1); - const e1 = testElement.get(0); - t.equal(e1.vertices0, 1); - t.equal(e1.vertices1, 2); - t.equal(e1.vertices2, 3); - - const testElement2 = bucket.arrays.test.elementArray2; - t.equal(testElement2.length, 1); - const e2 = testElement2.get(0); - t.equal(e2.vertices0, 17); - t.equal(e2.vertices1, 42); + t.equal(bucket.arrays.layoutVertexArray.arrayBuffer, transferables[0]); + t.equal(bucket.arrays.elementArray.arrayBuffer, transferables[1]); + t.equal(bucket.arrays.elementArray2.arrayBuffer, transferables[2]); + t.equal(bucket.arrays.layerData.layerid.paintVertexArray.arrayBuffer, transferables[3]); t.end(); }); @@ -258,36 +210,5 @@ test('Bucket', (t) => { t.end(); }); - t.test('add features', (t) => { - const bucket = create(); - - bucket.populate([createFeature(17, 42)], createOptions()); - - const testVertex = bucket.arrays.test.layoutVertexArray; - t.equal(testVertex.length, 1); - const v0 = testVertex.get(0); - t.equal(v0.a_box0, 34); - t.equal(v0.a_box1, 84); - const testPaintVertex = bucket.arrays.test.paintVertexArrays.layerid; - t.equal(testPaintVertex.length, 1); - const p0 = testPaintVertex.get(0); - t.equal(p0.a_map, 17); - - const testElement = bucket.arrays.test.elementArray; - t.equal(testElement.length, 1); - const e1 = testElement.get(0); - t.equal(e1.vertices0, 1); - t.equal(e1.vertices1, 2); - t.equal(e1.vertices2, 3); - - const testElement2 = bucket.arrays.test.elementArray2; - t.equal(testElement2.length, 1); - const e2 = testElement2.get(0); - t.equal(e2.vertices0, 17); - t.equal(e2.vertices1, 42); - - t.end(); - }); - t.end(); }); diff --git a/test/js/data/fill_bucket.test.js b/test/js/data/fill_bucket.test.js index c417541e7ef..6860cc86d10 100644 --- a/test/js/data/fill_bucket.test.js +++ b/test/js/data/fill_bucket.test.js @@ -33,7 +33,6 @@ function createPolygon(numPoints) { test('FillBucket', (t) => { const layer = new StyleLayer({ id: 'test', type: 'fill', layout: {} }); const bucket = new FillBucket({ layers: [layer] }); - bucket.createArrays(); bucket.addFeature(createFeature([[ new Point(0, 0), @@ -71,7 +70,6 @@ test('FillBucket segmentation', (t) => { layer.updatePaintTransition('fill-color', [], {}); const bucket = new FillBucket({ layers: [layer] }); - bucket.createArrays(); // first add an initial, small feature to make sure the next one starts at // a non-zero offset @@ -83,7 +81,7 @@ test('FillBucket segmentation', (t) => { createPolygon(128) ])); - const arrays = bucket.arrays.fill; + const arrays = bucket.arrays; // Each polygon must fit entirely within a segment, so we expect the // first segment to include the first feature and the first polygon @@ -103,9 +101,9 @@ test('FillBucket segmentation', (t) => { primitiveLength: 126 }); - t.equal(arrays.paintVertexArrays.test.length, 266); - for (let i = 0; i < arrays.paintVertexArrays.test.length; i++) { - const vertex = arrays.paintVertexArrays.test.get(i); + t.equal(arrays.layerData.test.paintVertexArray.length, 266); + for (let i = 0; i < arrays.layerData.test.paintVertexArray.length; i++) { + const vertex = arrays.layerData.test.paintVertexArray.get(i); t.deepEqual([ vertex['a_color0'], vertex['a_color1'], diff --git a/test/js/data/line_bucket.test.js b/test/js/data/line_bucket.test.js index 5881d8bfff2..b580749efd4 100644 --- a/test/js/data/line_bucket.test.js +++ b/test/js/data/line_bucket.test.js @@ -16,7 +16,6 @@ const feature = vt.layers.road.feature(0); test('LineBucket', (t) => { const layer = new StyleLayer({ id: 'test', type: 'line', layout: {} }); const bucket = new LineBucket({ layers: [layer] }); - bucket.createArrays(); const pointWithScale = new Point(0, 0); pointWithScale.scale = 10; diff --git a/test/js/data/symbol_bucket.test.js b/test/js/data/symbol_bucket.test.js index 865a3f1e68b..2678102e3cf 100644 --- a/test/js/data/symbol_bucket.test.js +++ b/test/js/data/symbol_bucket.test.js @@ -92,3 +92,15 @@ test('SymbolBucket integer overflow', (t) => { t.ok(util.warnOnce.getCall(1).calledWithMatch(/Too many (symbols|glyphs) being rendered in a tile./)); t.end(); }); + +test('SymbolBucket redo placement', (t) => { + const bucket = bucketSetup(); + const options = {iconDependencies: {}, glyphDependencies: {}}; + + bucket.populate([feature], options); + bucket.prepare(stacks, {}); + bucket.place(collision); + bucket.place(collision); + + t.end(); +}); diff --git a/test/js/source/worker_tile.test.js b/test/js/source/worker_tile.test.js index 90a42d0944e..5949872f5e8 100644 --- a/test/js/source/worker_tile.test.js +++ b/test/js/source/worker_tile.test.js @@ -44,10 +44,6 @@ test('WorkerTile#parse', (t) => { test('WorkerTile#parse skips hidden layers', (t) => { const layerIndex = new StyleLayerIndex([{ - id: 'test', - source: 'source', - type: 'circle' - }, { id: 'test-hidden', source: 'source', type: 'fill', @@ -57,7 +53,7 @@ test('WorkerTile#parse skips hidden layers', (t) => { const tile = createWorkerTile(); tile.parse(createWrapper(), layerIndex, {}, (err, result) => { t.ifError(err); - t.equal(Object.keys(result.buckets[0].arrays).length, 1); + t.equal(result.buckets.length, 0); t.end(); }); });