Skip to content

Commit

Permalink
Encapsulate SymbolBucket's unique requirements
Browse files Browse the repository at this point in the history
SymbolBucket is in several ways the "odd bucket out":

* It's the only bucket type that works with multiple program interfaces -- one for glyphs, one for icons, and one for collision boxes.
* It's the only bucket type whose instances are reused to build buffers multiple times.

Previously, the Bucket base class was generalized such that it could support multiple program interfaces for any Bucket subtype, and re-create buffers at any time. However, this added complexity to all subtypes other than Symbol.

Now, SymbolBucket encapsulates its differences:

* It uses ArrayGroup/BufferGroup directly, creating one for each of its three interfaces. In turn, the other bucket types, their corresponding layer rendering functions, and the Bucket base class, can all assume a single program interface.
* It recreates these arrays when needed, while the Bucket base class creates them once, in the constructor.
  • Loading branch information
jfirebaugh committed Oct 28, 2016
1 parent 3252ad1 commit 46a73c4
Show file tree
Hide file tree
Showing 18 changed files with 310 additions and 379 deletions.
40 changes: 8 additions & 32 deletions js/data/bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ const ArrayGroup = require('./array_group');
const BufferGroup = require('./buffer_group');
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.
Expand All @@ -25,23 +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;

if (options.arrays) {
this.bufferGroups = util.mapObject(options.arrays, (arrayGroup, programName) => {
return new BufferGroup(this.programInterfaces[programName], options.layers, options.zoom, arrayGroup);
});
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);
Expand All @@ -50,39 +45,20 @@ class Bucket {
}
}

createArrays() {
this.arrays = util.mapObject(this.programInterfaces, (programInterface) => {
return new ArrayGroup(programInterface, this.layers, this.zoom);
});
}

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();
}
}

Expand Down
105 changes: 51 additions & 54 deletions js/data/bucket/circle_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down
82 changes: 40 additions & 42 deletions js/data/bucket/fill_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 46a73c4

Please sign in to comment.