diff --git a/flow-typed/vector-tile.js b/flow-typed/vector-tile.js index 8c2af514681..260b78fa7e8 100644 --- a/flow-typed/vector-tile.js +++ b/flow-typed/vector-tile.js @@ -26,6 +26,7 @@ declare module "vector-tile" { } declare class VectorTileFeatureImpl { + static types: ['Unknown', 'Point', 'LineString', 'Polygon']; toGeoJSON(x: number, y: number, z: number): GeoJSONFeature; } diff --git a/src/data/array_group.js b/src/data/array_group.js index 8cd6fbaf9eb..784be935c33 100644 --- a/src/data/array_group.js +++ b/src/data/array_group.js @@ -1,9 +1,23 @@ +// @flow const ProgramConfiguration = require('./program_configuration'); const createVertexArrayType = require('./vertex_array_type'); +import type StyleLayer from '../style/style_layer'; +import type {ProgramInterface, PaintPropertyStatistics} from './program_configuration'; +import type { + StructArray, + SerializedStructArray, + SerializedStructArrayType +} from '../util/struct_array'; + class Segment { - constructor(vertexOffset, primitiveOffset) { + vertexOffset: number; + primitiveOffset: number; + vertexLength: number; + primitiveLength: number; + + constructor(vertexOffset: number, primitiveOffset: number) { this.vertexOffset = vertexOffset; this.primitiveOffset = primitiveOffset; this.vertexLength = 0; @@ -11,6 +25,28 @@ class Segment { } } +export type {Segment as Segment}; + +export type SerializedArrayGroup = { + layoutVertexArray: SerializedStructArray, + dynamicLayoutVertexArray: SerializedStructArray, + elementArray: SerializedStructArray, + elementArray2: SerializedStructArray, + paintVertexArrays: {[string]: { + array: SerializedStructArray, + type: SerializedStructArrayType + }}, + segments: Array, + segments2: Array +} + +type LayerData = { + layer: StyleLayer, + programConfiguration: ProgramConfiguration, + paintVertexArray: StructArray, + paintPropertyStatistics: PaintPropertyStatistics +} + /** * A class that manages vertex and element arrays for a bucket. It handles initialization, * serialization for transfer to the main thread, and certain intervening mutations. @@ -33,7 +69,18 @@ class Segment { * @private */ class ArrayGroup { - constructor(programInterface, layers, zoom) { + static MAX_VERTEX_ARRAY_LENGTH: number; + + globalProperties: {zoom: number}; + layoutVertexArray: StructArray; + dynamicLayoutVertexArray: StructArray; + elementArray: StructArray; + elementArray2: StructArray; + layerData: {[string]: LayerData}; + segments: Array; + segments2: Array; + + constructor(programInterface: ProgramInterface, layers: Array, zoom: number) { this.globalProperties = {zoom}; const LayoutVertexArrayType = createVertexArrayType(programInterface.layoutAttributes); @@ -66,7 +113,7 @@ class ArrayGroup { this.segments2 = []; } - prepareSegment(numVertices) { + prepareSegment(numVertices: number): Segment { let segment = this.segments[this.segments.length - 1]; if (!segment || segment.vertexLength + numVertices > ArrayGroup.MAX_VERTEX_ARRAY_LENGTH) { segment = new Segment(this.layoutVertexArray.length, this.elementArray.length); @@ -75,7 +122,7 @@ class ArrayGroup { return segment; } - prepareSegment2(numVertices) { + prepareSegment2(numVertices: number): Segment { let segment = this.segments2[this.segments2.length - 1]; if (!segment || segment.vertexLength + numVertices > ArrayGroup.MAX_VERTEX_ARRAY_LENGTH) { segment = new Segment(this.layoutVertexArray.length, this.elementArray2.length); @@ -84,7 +131,7 @@ class ArrayGroup { return segment; } - populatePaintArrays(featureProperties) { + populatePaintArrays(featureProperties: Object) { for (const key in this.layerData) { const layerData = this.layerData[key]; if (layerData.paintVertexArray.bytesPerElement === 0) continue; @@ -102,7 +149,7 @@ class ArrayGroup { return this.layoutVertexArray.length === 0; } - serialize(transferables) { + serialize(transferables?: Array): SerializedArrayGroup { return { layoutVertexArray: this.layoutVertexArray.serialize(transferables), dynamicLayoutVertexArray: this.dynamicLayoutVertexArray && this.dynamicLayoutVertexArray.serialize(transferables), @@ -115,7 +162,7 @@ class ArrayGroup { } } -function serializePaintVertexArrays(layerData, transferables) { +function serializePaintVertexArrays(layerData: {[string]: LayerData}, transferables?: Array) { const paintVertexArrays = {}; for (const layerId in layerData) { const inputArray = layerData[layerId].paintVertexArray; diff --git a/src/data/bucket.js b/src/data/bucket.js index 9b09dcbff06..b607e9496cd 100644 --- a/src/data/bucket.js +++ b/src/data/bucket.js @@ -1,8 +1,37 @@ +// @flow const ArrayGroup = require('./array_group'); const BufferGroup = require('./buffer_group'); const util = require('../util/util'); +import type CollisionBoxArray from '../symbol/collision_box'; +import type Style from '../style/style'; +import type StyleLayer from '../style/style_layer'; +import type {ProgramInterface} from './program_configuration'; +import type FeatureIndex, {IndexedFeature} from './feature_index'; +import type {SerializedArrayGroup} from './array_group'; + +export type BucketParameters = { + index: number, + layers: Array, + zoom: number, + overscaling: number, + collisionBoxArray: CollisionBoxArray, + arrays?: SerializedArrayGroup +} + +export type PopulateParameters = { + featureIndex: FeatureIndex, + iconDependencies: {}, + glyphDependencies: {} +} + +export type SerializedBucket = { + zoom: number, + layerIds: Array, + arrays: SerializedArrayGroup +} + /** * The `Bucket` class is the single point of knowledge about turning vector * tiles into WebGL buffers. @@ -27,16 +56,41 @@ const util = require('../util/util'); * @private */ class Bucket { - /** - * @param options - * @param {number} options.zoom Zoom level of the buffers being built. May be - * a fractional zoom level. - * @param options.layer A Mapbox style layer object - * @param {Object.} options.buffers The set of `Buffer`s being - * built for this tile. This object facilitates sharing of `Buffer`s be - between `Bucket`s. - */ - constructor (options, programInterface) { + index: number; + zoom: number; + overscaling: number; + layers: Array; + buffers: BufferGroup; + arrays: ArrayGroup; + + +addFeature: (feature: VectorTileFeature) => void; + + static deserialize(input: Array, style: Style): {[string]: Bucket} { + const output = {}; + + // Guard against the case where the map's style has been set to null while + // this bucket has been parsing. + if (!style) return output; + + for (const serialized of input) { + const layers = serialized.layerIds + .map((id) => style.getLayer(id)) + .filter(Boolean); + + if (layers.length === 0) { + continue; + } + + const bucket = layers[0].createBucket(util.extend({layers}, serialized)); + for (const layer of layers) { + output[layer.id] = bucket; + } + } + + return output; + } + + constructor(options: BucketParameters, programInterface: ProgramInterface) { this.zoom = options.zoom; this.overscaling = options.overscaling; this.layers = options.layers; @@ -49,7 +103,7 @@ class Bucket { } } - populate(features, options) { + populate(features: Array, options: PopulateParameters) { for (const feature of features) { if (this.layers[0].filter(feature)) { this.addFeature(feature); @@ -66,7 +120,7 @@ class Bucket { return this.arrays.isEmpty(); } - serialize(transferables) { + serialize(transferables?: Array): SerializedBucket { return { zoom: this.zoom, layerIds: this.layers.map((l) => l.id), @@ -84,34 +138,9 @@ class Bucket { destroy() { if (this.buffers) { this.buffers.destroy(); - this.buffers = null; + (this : any).buffers = null; } } } module.exports = Bucket; - -Bucket.deserialize = function(input, style) { - // Guard against the case where the map's style has been set to null while - // this bucket has been parsing. - if (!style) return; - - const output = {}; - - for (const serialized of input) { - const layers = serialized.layerIds - .map((id) => style.getLayer(id)) - .filter(Boolean); - - if (layers.length === 0) { - continue; - } - - const bucket = layers[0].createBucket(util.extend({layers}, serialized)); - for (const layer of layers) { - output[layer.id] = bucket; - } - } - - return output; -}; diff --git a/src/data/bucket/circle_bucket.js b/src/data/bucket/circle_bucket.js index b82e7244739..f714b691a97 100644 --- a/src/data/bucket/circle_bucket.js +++ b/src/data/bucket/circle_bucket.js @@ -1,9 +1,13 @@ +// @flow const Bucket = require('../bucket'); const createElementArrayType = require('../element_array_type'); const loadGeometry = require('../load_geometry'); const EXTENT = require('../extent'); +import type {BucketParameters} from '../bucket'; +import type {ProgramInterface} from '../program_configuration'; + const circleInterface = { layoutAttributes: [ {name: 'a_pos', components: 2, type: 'Int16'} @@ -35,11 +39,13 @@ function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) { * @private */ class CircleBucket extends Bucket { - constructor(options) { + static programInterface: ProgramInterface; + + constructor(options: BucketParameters) { super(options, circleInterface); } - addFeature(feature) { + addFeature(feature: VectorTileFeature) { const arrays = this.arrays; for (const ring of loadGeometry(feature)) { diff --git a/src/data/bucket/fill_bucket.js b/src/data/bucket/fill_bucket.js index 38b606679af..656161144bf 100644 --- a/src/data/bucket/fill_bucket.js +++ b/src/data/bucket/fill_bucket.js @@ -1,3 +1,4 @@ +// @flow const Bucket = require('../bucket'); const createElementArrayType = require('../element_array_type'); @@ -7,6 +8,9 @@ const classifyRings = require('../../util/classify_rings'); const assert = require('assert'); const EARCUT_MAX_RINGS = 500; +import type {BucketParameters} from '../bucket'; +import type {ProgramInterface} from '../program_configuration'; + const fillInterface = { layoutAttributes: [ {name: 'a_pos', components: 2, type: 'Int16'} @@ -22,11 +26,13 @@ const fillInterface = { }; class FillBucket extends Bucket { - constructor(options) { + static programInterface: ProgramInterface; + + constructor(options: BucketParameters) { super(options, fillInterface); } - addFeature(feature) { + addFeature(feature: VectorTileFeature) { const arrays = this.arrays; for (const polygon of classifyRings(loadGeometry(feature), EARCUT_MAX_RINGS)) { diff --git a/src/data/bucket/fill_extrusion_bucket.js b/src/data/bucket/fill_extrusion_bucket.js index c0270d82475..5556c18e6a5 100644 --- a/src/data/bucket/fill_extrusion_bucket.js +++ b/src/data/bucket/fill_extrusion_bucket.js @@ -1,3 +1,4 @@ +// @flow const Bucket = require('../bucket'); const createElementArrayType = require('../element_array_type'); @@ -8,6 +9,9 @@ const classifyRings = require('../../util/classify_rings'); const assert = require('assert'); const EARCUT_MAX_RINGS = 500; +import type {BucketParameters} from '../bucket'; +import type {ProgramInterface} from '../program_configuration'; + const fillExtrusionInterface = { layoutAttributes: [ {name: 'a_pos', components: 2, type: 'Int16'}, @@ -41,11 +45,13 @@ function addVertex(vertexArray, x, y, nx, ny, nz, t, e) { } class FillExtrusionBucket extends Bucket { - constructor(options) { + static programInterface: ProgramInterface; + + constructor(options: BucketParameters) { super(options, fillExtrusionInterface); } - addFeature(feature) { + addFeature(feature: VectorTileFeature) { const arrays = this.arrays; for (const polygon of classifyRings(loadGeometry(feature), EARCUT_MAX_RINGS)) { diff --git a/src/data/bucket/line_bucket.js b/src/data/bucket/line_bucket.js index 0fff76a26e7..59c0f038bfa 100644 --- a/src/data/bucket/line_bucket.js +++ b/src/data/bucket/line_bucket.js @@ -1,9 +1,15 @@ +// @flow const Bucket = require('../bucket'); const createElementArrayType = require('../element_array_type'); const loadGeometry = require('../load_geometry'); const EXTENT = require('../extent'); -const VectorTileFeature = require('vector-tile').VectorTileFeature; +const vectorTileFeatureTypes = require('vector-tile').VectorTileFeature.types; + +import type {BucketParameters} from '../bucket'; +import type {ProgramInterface} from '../program_configuration'; +import type Point from 'point-geometry'; +import type {Segment} from '../array_group'; // NOTE ON EXTRUDE SCALE: // scale the extrusion vector so that the normal length is this value. @@ -77,11 +83,18 @@ function addLineVertex(layoutVertexBuffer, point, extrude, tx, ty, dir, linesofa * @private */ class LineBucket extends Bucket { - constructor(options) { + static programInterface: ProgramInterface; + + distance: number; + e1: number; + e2: number; + e3: number; + + constructor(options: BucketParameters) { super(options, lineInterface); } - addFeature(feature) { + addFeature(feature: VectorTileFeature) { const layout = this.layers[0].layout; const join = layout['line-join']; const cap = layout['line-cap']; @@ -93,9 +106,9 @@ class LineBucket extends Bucket { } } - addLine(vertices, feature, join, cap, miterLimit, roundLimit) { + addLine(vertices: Array, feature: VectorTileFeature, join: string, cap: string, miterLimit: number, roundLimit: number) { const featureProperties = feature.properties; - const isPolygon = VectorTileFeature.types[feature.type] === 'Polygon'; + const isPolygon = vectorTileFeatureTypes[feature.type] === 'Polygon'; // If the line has duplicate vertices at the ends, adjust start/length to remove them. let len = vertices.length; @@ -125,7 +138,13 @@ class LineBucket extends Bucket { const beginCap = cap, endCap = isPolygon ? 'butt' : cap; let startOfLine = true; - let currentVertex, prevVertex, nextVertex, prevNormal, nextNormal, offsetA, offsetB; + let currentVertex; + let prevVertex = ((undefined : any): Point); + let nextVertex = ((undefined : any): Point); + let prevNormal = ((undefined : any): Point); + let nextNormal = ((undefined : any): Point); + let offsetA; + let offsetB; // the last three vertices added this.e1 = this.e2 = this.e3 = -1; @@ -365,7 +384,13 @@ class LineBucket extends Bucket { * @param {boolean} round whether this is a round cap * @private */ - addCurrentVertex(currentVertex, distance, normal, endLeft, endRight, round, segment) { + addCurrentVertex(currentVertex: Point, + distance: number, + normal: Point, + endLeft: number, + endRight: number, + round: boolean, + segment: Segment) { const tx = round ? 1 : 0; let extrude; const arrays = this.arrays; @@ -414,7 +439,11 @@ class LineBucket extends Bucket { * @param {boolean} whether the line is turning left or right at this angle * @private */ - addPieSliceVertex(currentVertex, distance, extrude, lineTurnsLeft, segment) { + addPieSliceVertex(currentVertex: Point, + distance: number, + extrude: Point, + lineTurnsLeft: boolean, + segment: Segment) { const ty = lineTurnsLeft ? 1 : 0; extrude = extrude.mult(lineTurnsLeft ? -1 : 1); const arrays = this.arrays; diff --git a/src/data/bucket/symbol_bucket.js b/src/data/bucket/symbol_bucket.js index 330aec352cf..d35722354d4 100644 --- a/src/data/bucket/symbol_bucket.js +++ b/src/data/bucket/symbol_bucket.js @@ -1,3 +1,4 @@ +// @flow const Point = require('point-geometry'); const ArrayGroup = require('../array_group'); @@ -19,7 +20,7 @@ const loadGeometry = require('../load_geometry'); const CollisionFeature = require('../../symbol/collision_feature'); const findPoleOfInaccessibility = require('../../util/find_pole_of_inaccessibility'); const classifyRings = require('../../util/classify_rings'); -const VectorTileFeature = require('vector-tile').VectorTileFeature; +const vectorTileFeatureTypes = require('vector-tile').VectorTileFeature.types; const createStructArrayType = require('../../util/struct_array'); const shapeText = Shaping.shapeText; @@ -28,6 +29,22 @@ const WritingMode = Shaping.WritingMode; const getGlyphQuads = Quads.getGlyphQuads; const getIconQuads = Quads.getIconQuads; +import type {BucketParameters, PopulateParameters} from '../bucket'; +import type {ProgramInterface} from '../program_configuration'; +import type {IndexedFeature} from '../feature_index'; + +type SymbolBucketParameters = BucketParameters & { + sdfIcons: boolean, + iconsNeedLinear: boolean, + fontstack: any, + textSizeData: any, + iconSizeData: any, + placedGlyphArray: any, + placedIconArray: any, + glyphOffsetArray: any, + lineVertexArray: any, +} + const PlacedSymbolArray = createStructArrayType({ members: [ { type: 'Int16', name: 'anchorX' }, @@ -175,7 +192,39 @@ function addCollisionBoxVertex(layoutVertexArray, point, anchor, extrude, maxZoo * @private */ class SymbolBucket { - constructor(options) { + static programInterfaces: { + glyph: ProgramInterface, + icon: ProgramInterface, + collisionBox: ProgramInterface + }; + + static MAX_INSTANCES: number; + + static addDynamicAttributes: any; + + collisionBoxArray: any; + zoom: number; + overscaling: number; + layers: any; + index: any; + sdfIcons: boolean; + iconsNeedLinear: boolean; + fontstack: any; + symbolInterfaces: any; + buffers: any; + textSizeData: any; + iconSizeData: any; + placedGlyphArray: any; + placedIconArray: any; + glyphOffsetArray: any; + lineVertexArray: any; + features: any; + arrays: any; + symbolInstances: any; + tilePixelRatio: any; + compareText: any; + + constructor(options: SymbolBucketParameters) { this.collisionBoxArray = options.collisionBoxArray; this.zoom = options.zoom; @@ -213,7 +262,7 @@ class SymbolBucket { } } - populate(features, options) { + populate(features: Array, options: PopulateParameters) { const layer = this.layers[0]; const layout = layer.layout; const textFont = layout['text-font']; @@ -266,7 +315,7 @@ class SymbolBucket { sourceLayerIndex: feature.sourceLayerIndex, geometry: loadGeometry(feature), properties: feature.properties, - type: VectorTileFeature.types[feature.type] + type: vectorTileFeatureTypes[feature.type] }); if (icon) { @@ -304,7 +353,7 @@ class SymbolBucket { return statistics; } - serialize(transferables) { + serialize(transferables?: Array) { return { zoom: this.zoom, layerIds: this.layers.map((l) => l.id), @@ -336,7 +385,7 @@ class SymbolBucket { }); } - prepare(stacks, icons) { + prepare(stacks: any, icons: any) { this.symbolInstances = []; const tileSize = 512 * this.overscaling; @@ -435,7 +484,7 @@ class SymbolBucket { * source.) * @private */ - addFeature(feature, shapedTextOrientations, shapedIcon) { + addFeature(feature: any, shapedTextOrientations: any, shapedIcon: any) { const layoutTextSize = this.layers[0].getLayoutValue('text-size', {zoom: this.zoom + 1}, feature.properties); const layoutIconSize = this.layers[0].getLayoutValue('icon-size', {zoom: this.zoom + 1}, feature.properties); @@ -531,7 +580,7 @@ class SymbolBucket { } } - anchorIsTooClose(text, repeatDistance, anchor) { + anchorIsTooClose(text: any, repeatDistance: any, anchor: any) { const compareText = this.compareText; if (!(text in compareText)) { compareText[text] = []; @@ -549,7 +598,7 @@ class SymbolBucket { return false; } - place(collisionTile, showCollisionBoxes) { + place(collisionTile: any, showCollisionBoxes: any) { // Calculate which labels can be shown and when they can be shown and // create the bufers used for rendering. @@ -702,7 +751,7 @@ class SymbolBucket { if (showCollisionBoxes) this.addToDebugBuffers(collisionTile); } - addSymbols(arrays, quads, scale, sizeVertex, keepUpright, lineOffset, alongLine, placementAngle, featureProperties, writingModes, labelAnchor, lineStartIndex, lineLength, placedSymbolArray) { + addSymbols(arrays: any, quads: any, scale: any, sizeVertex: any, keepUpright: any, lineOffset: any, alongLine: any, placementAngle: any, featureProperties: any, writingModes: any, labelAnchor: any, lineStartIndex: any, lineLength: any, placedSymbolArray: any) { const elementArray = arrays.elementArray; const layoutVertexArray = arrays.layoutVertexArray; const dynamicLayoutVertexArray = arrays.dynamicLayoutVertexArray; @@ -761,7 +810,7 @@ class SymbolBucket { arrays.populatePaintArrays(featureProperties); } - addToDebugBuffers(collisionTile) { + addToDebugBuffers(collisionTile: any) { const arrays = this.arrays.collisionBox; const layoutVertexArray = arrays.layoutVertexArray; const elementArray = arrays.elementArray; @@ -830,9 +879,9 @@ class SymbolBucket { * * @private */ - addSymbolInstance(anchor, line, shapedTextOrientations, shapedIcon, layer, addToBuffers, collisionBoxArray, featureIndex, sourceLayerIndex, bucketIndex, - textBoxScale, textPadding, textAlongLine, textOffset, - iconBoxScale, iconPadding, iconAlongLine, iconOffset, globalProperties, featureProperties) { + addSymbolInstance(anchor: any, line: any, shapedTextOrientations: any, shapedIcon: any, layer: any, addToBuffers: any, collisionBoxArray: any, featureIndex: any, sourceLayerIndex: any, bucketIndex: any, + textBoxScale: any, textPadding: any, textAlongLine: any, textOffset: any, + iconBoxScale: any, iconPadding: any, iconAlongLine: any, iconOffset: any, globalProperties: any, featureProperties: any) { let textCollisionFeature, iconCollisionFeature; let iconQuads = []; @@ -891,10 +940,10 @@ class SymbolBucket { // For {text,icon}-size, get the bucket-level data that will be needed by // the painter to set symbol-size-related uniforms function getSizeData(tileZoom, layer, sizeProperty) { - const sizeData = { - isFeatureConstant: layer.isLayoutValueFeatureConstant(sizeProperty), - isZoomConstant: layer.isLayoutValueZoomConstant(sizeProperty) - }; + const sizeData = {}; + + sizeData.isFeatureConstant = layer.isLayoutValueFeatureConstant(sizeProperty); + sizeData.isZoomConstant = layer.isLayoutValueZoomConstant(sizeProperty); if (sizeData.isFeatureConstant) { sizeData.layoutSize = layer.getLayoutValue(sizeProperty, {zoom: tileZoom + 1}); diff --git a/src/data/buffer.js b/src/data/buffer.js index c3811b7109c..9777600628a 100644 --- a/src/data/buffer.js +++ b/src/data/buffer.js @@ -1,3 +1,13 @@ +// @flow + +import type { + StructArray, + StructArrayMember, + SerializedStructArray, + SerializedStructArrayType +} from '../util/struct_array'; + +import type {Program} from './program_configuration'; /** * @enum {string} AttributeType @@ -9,6 +19,8 @@ const AttributeType = { Uint8: 'UNSIGNED_BYTE', Int16: 'SHORT', Uint16: 'UNSIGNED_SHORT', + Int32: 'INT', + Uint32: 'UNSIGNED_INT', Float32: 'FLOAT' }; @@ -18,13 +30,27 @@ const AttributeType = { * @private */ class Buffer { + static BufferType: {[string]: 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER'}; + arrayBuffer: ?ArrayBuffer; + length: number; + attributes: Array; + itemSize: number; + type: 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER'; + arrayType: SerializedStructArrayType; + dynamicDraw: ?boolean; + gl: WebGLRenderingContext; + buffer: ?WebGLBuffer; + /** * @param {Object} array A serialized StructArray. * @param {Object} arrayType A serialized StructArrayType. * @param {BufferType} type * @param {boolean} dynamicDraw Whether this buffer will be repeatedly updated. */ - constructor(array, arrayType, type, dynamicDraw) { + constructor(array: SerializedStructArray, + arrayType: SerializedStructArrayType, + type: 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER', + dynamicDraw?: boolean) { this.arrayBuffer = array.arrayBuffer; this.length = array.length; this.attributes = arrayType.members; @@ -34,7 +60,7 @@ class Buffer { this.dynamicDraw = dynamicDraw; } - static fromStructArray(array, type) { + static fromStructArray(array: StructArray, type: 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER') { return new Buffer(array.serialize(), array.constructor.serialize(), type); } @@ -42,8 +68,8 @@ class Buffer { * Bind this buffer to a WebGL context. * @param gl The WebGL context */ - bind(gl) { - const type = gl[this.type]; + bind(gl: WebGLRenderingContext) { + const type: number = (gl : any)[this.type]; if (!this.buffer) { this.gl = gl; @@ -63,17 +89,14 @@ class Buffer { } } - /* - * @param {Object} array A serialized StructArray. - */ - updateData(array) { + updateData(array: SerializedStructArray) { this.arrayBuffer = array.arrayBuffer; } - enableAttributes (gl, program) { + enableAttributes(gl: WebGLRenderingContext, program: Program) { for (let j = 0; j < this.attributes.length; j++) { const member = this.attributes[j]; - const attribIndex = program[member.name]; + const attribIndex: number | void = program[member.name]; if (attribIndex !== undefined) { gl.enableVertexAttribArray(attribIndex); } @@ -86,16 +109,16 @@ class Buffer { * @param program The active WebGL program * @param vertexOffset Index of the starting vertex of the segment */ - setVertexAttribPointers(gl, program, vertexOffset) { + setVertexAttribPointers(gl: WebGLRenderingContext, program: Program, vertexOffset: number) { for (let j = 0; j < this.attributes.length; j++) { const member = this.attributes[j]; - const attribIndex = program[member.name]; + const attribIndex: number | void = program[member.name]; if (attribIndex !== undefined) { gl.vertexAttribPointer( attribIndex, member.components, - gl[AttributeType[member.type]], + (gl : any)[AttributeType[member.type]], false, this.arrayType.bytesPerElement, member.offset + (this.arrayType.bytesPerElement * vertexOffset || 0) @@ -106,7 +129,6 @@ class Buffer { /** * Destroy the GL buffer bound to the given WebGL context - * @param gl The WebGL context */ destroy() { if (this.buffer) { diff --git a/src/data/buffer_group.js b/src/data/buffer_group.js index 95051028bb2..51b8a04b2a0 100644 --- a/src/data/buffer_group.js +++ b/src/data/buffer_group.js @@ -1,3 +1,4 @@ +// @flow const util = require('../util/util'); const Buffer = require('./buffer'); @@ -5,6 +6,11 @@ const ProgramConfiguration = require('./program_configuration'); const createVertexArrayType = require('./vertex_array_type'); const VertexArrayObject = require('../render/vertex_array_object'); +import type StyleLayer from '../style/style_layer'; +import type {ProgramInterface} from './program_configuration'; +import type {SerializedArrayGroup} from './array_group'; +import type {StructArray} from '../util/struct_array'; + /** * A class containing vertex and element arrays for a bucket, ready for use in * a WebGL program. See {@link ArrayGroup} for details. @@ -12,24 +18,36 @@ const VertexArrayObject = require('../render/vertex_array_object'); * @private */ class BufferGroup { - constructor(programInterface, layers, zoom, arrays) { + layoutVertexBuffer: Buffer; + dynamicLayoutVertexArray: StructArray; + dynamicLayoutVertexBuffer: Buffer; + elementBuffer: Buffer; + elementBuffer2: Buffer; + layerData: {[string]: { + programConfiguration: ProgramConfiguration, + paintVertexBuffer: ?Buffer + }}; + segments: Array; + segments2: Array; + + constructor(programInterface: ProgramInterface, layers: Array, zoom: number, arrays: SerializedArrayGroup) { const LayoutVertexArrayType = createVertexArrayType(programInterface.layoutAttributes); this.layoutVertexBuffer = new Buffer(arrays.layoutVertexArray, LayoutVertexArrayType.serialize(), Buffer.BufferType.VERTEX); - if (arrays.dynamicLayoutVertexArray) { + if (arrays.dynamicLayoutVertexArray && programInterface.dynamicLayoutAttributes) { const DynamicLayoutVertexArrayType = createVertexArrayType(programInterface.dynamicLayoutAttributes); this.dynamicLayoutVertexArray = new DynamicLayoutVertexArrayType(arrays.dynamicLayoutVertexArray); this.dynamicLayoutVertexBuffer = new Buffer(arrays.dynamicLayoutVertexArray, DynamicLayoutVertexArrayType.serialize(), Buffer.BufferType.VERTEX, true); } - if (arrays.elementArray) { + if (arrays.elementArray && programInterface.elementArrayType) { this.elementBuffer = new Buffer(arrays.elementArray, programInterface.elementArrayType.serialize(), Buffer.BufferType.ELEMENT); } - if (arrays.elementArray2) { + if (arrays.elementArray2 && programInterface.elementArrayType2) { this.elementBuffer2 = new Buffer(arrays.elementArray2, programInterface.elementArrayType2.serialize(), Buffer.BufferType.ELEMENT); } diff --git a/src/data/element_array_type.js b/src/data/element_array_type.js index 6f0190cd4bf..189130141c5 100644 --- a/src/data/element_array_type.js +++ b/src/data/element_array_type.js @@ -1,3 +1,4 @@ +// @flow const createStructArrayType = require('../util/struct_array'); @@ -8,7 +9,7 @@ module.exports = createElementArrayType; * arguments, it defaults to three components per element, forming triangles. * @private */ -function createElementArrayType(components) { +function createElementArrayType(components?: number) { return createStructArrayType({ members: [{ type: 'Uint16', diff --git a/src/data/extent.js b/src/data/extent.js index ed9dd5366e8..d8b5a73b0df 100644 --- a/src/data/extent.js +++ b/src/data/extent.js @@ -1,3 +1,4 @@ +// @flow /** * The maximum value of a coordinate in the internal tile coordinate system. Coordinates of diff --git a/src/data/feature_index.js b/src/data/feature_index.js index dfabead2e8d..1f55f5c8035 100644 --- a/src/data/feature_index.js +++ b/src/data/feature_index.js @@ -34,7 +34,7 @@ const FeatureIndexArray = createStructArrayType({ ] }); -type Feature = { +export type IndexedFeature = VectorTileFeature & { index: number, sourceLayerIndex: number, } @@ -92,7 +92,7 @@ class FeatureIndex { } } - insert(feature: Feature, bucketIndex: number) { + insert(feature: IndexedFeature, bucketIndex: number) { const key = this.featureIndexArray.length; this.featureIndexArray.emplaceBack(feature.index, feature.sourceLayerIndex, bucketIndex); const geometry = loadGeometry(feature); diff --git a/src/data/load_geometry.js b/src/data/load_geometry.js index e3f1ce83725..cc878a11e3f 100644 --- a/src/data/load_geometry.js +++ b/src/data/load_geometry.js @@ -1,3 +1,4 @@ +// @flow const util = require('../util/util'); const EXTENT = require('./extent'); @@ -16,8 +17,8 @@ function createBounds(bits) { } const boundsLookup = { - 15: createBounds(15), - 16: createBounds(16) + '15': createBounds(15), + '16': createBounds(16) }; /** @@ -29,7 +30,7 @@ const boundsLookup = { * in the specified number of bits. * @private */ -module.exports = function loadGeometry(feature, bits) { +module.exports = function loadGeometry(feature: VectorTileFeature, bits?: number) { const bounds = boundsLookup[bits || 16]; assert(bounds); diff --git a/src/data/pos_array.js b/src/data/pos_array.js index 13055223eb3..524289ec16a 100644 --- a/src/data/pos_array.js +++ b/src/data/pos_array.js @@ -1,3 +1,4 @@ +// @flow const createStructArrayType = require('../util/struct_array'); diff --git a/src/data/program_configuration.js b/src/data/program_configuration.js index d48211c09e4..776bc005508 100644 --- a/src/data/program_configuration.js +++ b/src/data/program_configuration.js @@ -5,9 +5,28 @@ const createVertexArrayType = require('./vertex_array_type'); const util = require('../util/util'); import type StyleLayer from '../style/style_layer'; +import type {ViewType, StructArray} from '../util/struct_array'; + +type LayoutAttribute = { + name: string, + type: ViewType, + components?: number +} + +type PaintAttribute = { + name?: string, + type: ViewType, + property: string, + components?: number, + multiplier?: number, + dimensions?: number, + zoomStops?: Array, + useIntegerZoom?: boolean +} type Attribute = { name: string, + type: ViewType, property: string, components: number, multiplier: number, @@ -45,9 +64,12 @@ export type PaintPropertyStatistics = { [property: string]: { max: number } } -type ProgramInterface = { - layoutAttributes?: Array, - paintAttributes?: Array +export type ProgramInterface = { + layoutAttributes: Array, + dynamicLayoutAttributes?: Array, + paintAttributes?: Array, + elementArrayType?: Class, + elementArrayType2?: Class, } export type Program = { @@ -80,8 +102,8 @@ class ProgramConfiguration { interpolationUniforms: Array; pragmas: { [string]: Pragmas }; cacheKey: string; - interface: ProgramInterface; - PaintVertexArray: any; + interface: ?ProgramInterface; + PaintVertexArray: Class; constructor() { this.attributes = []; @@ -89,7 +111,6 @@ class ProgramConfiguration { this.interpolationUniforms = []; this.pragmas = {}; this.cacheKey = ''; - this.interface = {}; } static createDynamic(programInterface: ProgramInterface, layer: StyleLayer, zoom: number) { @@ -334,7 +355,7 @@ function getPaintAttributeValue(attribute: Attribute, layer: StyleLayer, globalP return values.length === 1 ? values[0] : values; } -function normalizePaintAttribute(attribute: Attribute, layer: StyleLayer): Attribute { +function normalizePaintAttribute(attribute: PaintAttribute, layer: StyleLayer): Attribute { let name = attribute.name; // by default, construct the shader variable name for paint attribute diff --git a/src/data/raster_bounds_array.js b/src/data/raster_bounds_array.js index 85d98218117..13897c0bebe 100644 --- a/src/data/raster_bounds_array.js +++ b/src/data/raster_bounds_array.js @@ -1,3 +1,4 @@ +// @flow const createStructArrayType = require('../util/struct_array'); diff --git a/src/data/vertex_array_type.js b/src/data/vertex_array_type.js index 917620e048b..2b28b5c526a 100644 --- a/src/data/vertex_array_type.js +++ b/src/data/vertex_array_type.js @@ -1,6 +1,9 @@ +// @flow const createStructArrayType = require('../util/struct_array'); +import type {ViewType} from '../util/struct_array'; + module.exports = createVertexArrayType; /** @@ -8,7 +11,11 @@ module.exports = createVertexArrayType; * boundaries for best performance in WebGL. * @private */ -function createVertexArrayType(members) { +function createVertexArrayType(members: $ReadOnlyArray<{ + name: string, + type: ViewType, + +components?: number, +}>) { return createStructArrayType({ members: members, alignment: 4 diff --git a/src/render/painter.js b/src/render/painter.js index 22afbf67ec5..2bb8af82e47 100644 --- a/src/render/painter.js +++ b/src/render/painter.js @@ -444,7 +444,7 @@ class Painter { // ProgramInterface so that we don't dynamically link an unused // attribute at position 0, which can cause rendering to fail for an // entire layer (see #4607, #4728) - const layoutAttributes = configuration.interface.layoutAttributes || []; + const layoutAttributes = configuration.interface ? configuration.interface.layoutAttributes : []; for (let i = 0; i < layoutAttributes.length; i++) { gl.bindAttribLocation(program, i, layoutAttributes[i].name); } diff --git a/src/source/worker_tile.js b/src/source/worker_tile.js index f76cdd67f82..ea82b3fdde0 100644 --- a/src/source/worker_tile.js +++ b/src/source/worker_tile.js @@ -8,7 +8,7 @@ const util = require('../util/util'); const assert = require('assert'); import type {TileCoord} from './tile_coord'; -import type {SymbolBucket} from '../data/bucket/symbol_bucket'; +import type SymbolBucket from '../data/bucket/symbol_bucket'; import type {Actor} from '../util/actor'; import type {StyleLayerIndex} from '../style/style_layer_index'; import type { diff --git a/src/util/struct_array.js b/src/util/struct_array.js index 0f05cc5f388..a900cb2af11 100644 --- a/src/util/struct_array.js +++ b/src/util/struct_array.js @@ -9,18 +9,14 @@ module.exports = createStructArrayType; const viewTypes = { 'Int8': Int8Array, 'Uint8': Uint8Array, - 'Uint8Clamped': Uint8ClampedArray, 'Int16': Int16Array, 'Uint16': Uint16Array, 'Int32': Int32Array, 'Uint32': Uint32Array, - 'Float32': Float32Array, - 'Float64': Float64Array + 'Float32': Float32Array }; -/* eslint-disable no-undef */ -type ViewType = $Keys; -/* eslint-enable no-undef */ +export type ViewType = $Keys; /** * @typedef {Object} StructMember @@ -39,15 +35,17 @@ class Struct { _pos4: number; _pos8: number; _structArray: StructArray; + // The following properties are defined on the prototype of sub classes. size: number; alignment: number; + /** * @param {StructArray} structArray The StructArray the struct is stored in * @param {number} index The index of the struct in the StructArray. * @private */ - constructor(structArray, index) { + constructor(structArray: StructArray, index: number) { this._structArray = structArray; this._pos1 = index * this.size; this._pos2 = this._pos1 / 2; @@ -59,12 +57,32 @@ class Struct { const DEFAULT_CAPACITY = 128; const RESIZE_MULTIPLIER = 5; -type StructArrayMember = {| +export type StructArrayMember = { name: string, type: ViewType, components: number, offset: number -|}; +}; + +export type SerializedStructArray = { + length: number, + arrayBuffer: ArrayBuffer +}; + +export type SerializedStructArrayType = { + members: Array, + alignment: number, + bytesPerElement: number +}; + +type StructArrayTypeParameters = { + members: $ReadOnlyArray<{ + name: string, + type: ViewType, + +components?: number, + }>, + alignment?: number +}; /** * The StructArray class is inherited by the custom StructArrayType classes created with @@ -85,13 +103,15 @@ class StructArray { uint32: ?Uint32Array; float32: ?Float32Array; float64: ?Float64Array; - // The following properties aer defined on the prototype. + + // The following properties are defined on the prototype. members: Array; StructType: typeof Struct; bytesPerElement: number; _usedTypes: Array; emplaceBack: Function; - constructor(serialized?: {arrayBuffer: ArrayBuffer, length: number}) { + + constructor(serialized?: SerializedStructArray) { this.isTransferred = false; if (serialized !== undefined) { @@ -111,7 +131,7 @@ class StructArray { /** * Serialize the StructArray type. This serializes the *type* not an instance of the type. */ - static serialize() { + static serialize(): SerializedStructArrayType { return { members: this.prototype.members, alignment: this.prototype.StructType.prototype.alignment, @@ -122,7 +142,7 @@ class StructArray { /** * Serialize this StructArray instance */ - serialize(transferables?: Array) { + serialize(transferables?: Array): SerializedStructArray { assert(!this.isTransferred); this._trim(); @@ -213,7 +233,9 @@ class StructArray { } } -const structArrayTypeCache: {[key: string]: typeof StructArray} = {}; +export type { StructArray as StructArray }; + +const structArrayTypeCache: {[key: string]: Class} = {}; /** * `createStructArrayType` is used to create new `StructArray` types. @@ -251,11 +273,7 @@ const structArrayTypeCache: {[key: string]: typeof StructArray} = {}; * @private */ -function createStructArrayType(options: {| - members: Array<{type: ViewType, name: string, components?: number}>, - alignment?: number -|}): Class { - +function createStructArrayType(options: StructArrayTypeParameters): Class { const key = JSON.stringify(options); if (structArrayTypeCache[key]) { diff --git a/src/util/token.js b/src/util/token.js index 9102119adeb..0d875c4ccb7 100644 --- a/src/util/token.js +++ b/src/util/token.js @@ -1,4 +1,3 @@ - // @flow module.exports = resolveTokens; @@ -11,7 +10,7 @@ module.exports = resolveTokens; * @returns {string} the template with tokens replaced * @private */ -function resolveTokens(properties: {[key: string]: string}, text: string): string { +function resolveTokens(properties: Object, text: string): string { return text.replace(/{([^{}]+)}/g, (match, key: string) => { return key in properties ? properties[key] : ''; }); diff --git a/src/util/util.js b/src/util/util.js index 642a4c614bc..306aaf2379f 100644 --- a/src/util/util.js +++ b/src/util/util.js @@ -111,7 +111,7 @@ exports.asyncAll = function ( * * @private */ -exports.values = function (obj: {[key: string]: string}): Array { +exports.values = function(obj: {[key: string]: T}): Array { const result = []; for (const k in obj) { result.push(obj[k]);