From 92fbfb81b92413f55ed7d983ba105bba97641767 Mon Sep 17 00:00:00 2001 From: Molly Lloyd Date: Wed, 11 May 2016 18:25:01 -0700 Subject: [PATCH] [transferrable symbol buffer] declare new StructArrayTypes for SymbolInstances and SymbolQuads create SymbolInstancesArray StructArrayType add symbolinstances and quads to struct arrays populate symbolInstanceBuffer and symbolQuadsBuffer transfer symbol buffers from worker --> main thread add symbolInstances and symbolQuads to tile.js --- js/data/bucket/symbol_bucket.js | 60 +++++++++++++++++++++++++++++++++ js/source/tile.js | 6 ++++ js/source/worker_tile.js | 10 ++++++ js/symbol/symbol_instances.js | 37 ++++++++++++++++++++ js/symbol/symbol_quads.js | 56 ++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+) create mode 100644 js/symbol/symbol_instances.js create mode 100644 js/symbol/symbol_quads.js diff --git a/js/data/bucket/symbol_bucket.js b/js/data/bucket/symbol_bucket.js index 25c375d6be0..dbc3a9884d7 100644 --- a/js/data/bucket/symbol_bucket.js +++ b/js/data/bucket/symbol_bucket.js @@ -29,6 +29,8 @@ function SymbolBucket(options) { this.showCollisionBoxes = options.showCollisionBoxes; this.overscaling = options.overscaling; this.collisionBoxArray = options.collisionBoxArray; + this.symbolQuadsArray = options.symbolQuadsArray; + this.symbolInstancesArray = options.symbolInstancesArray; this.sdfIcons = options.sdfIcons; this.iconsNeedLinear = options.iconsNeedLinear; @@ -327,6 +329,11 @@ SymbolBucket.prototype.addFeature = function(lines, shapedText, shapedIcon, feat iconBoxScale, iconPadding, iconAlongLine)); } } + + for (var k = 0; k < this.symbolInstances.length; k++) { + this.addSymbolInstance(this.symbolInstances[k]); + } + }; SymbolBucket.prototype.anchorIsTooClose = function(text, repeatDistance, anchor) { @@ -558,3 +565,56 @@ function SymbolInstance(anchor, line, shapedText, shapedIcon, layout, addToBuffe shapedIcon, iconBoxScale, iconPadding, iconAlongLine, true); } } + +SymbolBucket.prototype.addSymbolInstance = function(symbolInstance) { + var startGlyphIndex, endGlyphIndex, iconQuadIndex; + var quads = symbolInstance.glyphQuads ? symbolInstance.glyphQuads : []; + for (var i = 0; i < quads.length; i++) { + if (i === 0) { + startGlyphIndex = this.addSymbolQuad(quads[i]); + } else if (i === quads.length - 1) { + endGlyphIndex = this.addSymbolQuad(quads[i]); + } else { + this.addSymbolQuad(quads[i]); + } + } + + if (symbolInstance.iconQuads && symbolInstance.iconQuads.length === 1) { + iconQuadIndex = this.addSymbolQuad(symbolInstance.iconQuads[0]); + } + + return this.symbolInstancesArray.emplaceBack( + startGlyphIndex || -1, + endGlyphIndex || -1, + iconQuadIndex || -1, + symbolInstance.x, + symbolInstance.y, + symbolInstance.index); + +}; + +SymbolBucket.prototype.addSymbolQuad = function(symbolQuad) { + return this.symbolQuadsArray.emplaceBack( + // anchorPoints + symbolQuad.anchorPoint.x, + symbolQuad.anchorPoint.y, + // corners + symbolQuad.tl.x, + symbolQuad.tl.y, + symbolQuad.tr.x, + symbolQuad.tr.y, + symbolQuad.bl.x, + symbolQuad.bl.y, + symbolQuad.br.x, + symbolQuad.br.y, + // texture + symbolQuad.tex.h, + symbolQuad.tex.w, + symbolQuad.tex.x, + symbolQuad.tex.y, + //angle + symbolQuad.angle, + // scales + symbolQuad.minScale, + symbolQuad.maxScale); +}; diff --git a/js/source/tile.js b/js/source/tile.js index 41a87799b40..18155eeba2a 100644 --- a/js/source/tile.js +++ b/js/source/tile.js @@ -9,6 +9,8 @@ var GeoJSONFeature = require('../util/vectortile_to_geojson'); var featureFilter = require('feature-filter'); var CollisionTile = require('../symbol/collision_tile'); var CollisionBoxArray = require('../symbol/collision_box'); +var SymbolInstancesArray = require('../symbol/symbol_instances'); +var SymbolQuadsArray = require('../symbol/symbol_quads'); module.exports = Tile; @@ -50,6 +52,8 @@ Tile.prototype = { this.collisionBoxArray = new CollisionBoxArray(data.collisionBoxArray); this.collisionTile = new CollisionTile(data.collisionTile, this.collisionBoxArray); + this.symbolInstancesArray = new SymbolInstancesArray(data.symbolInstancesArray); + this.symbolQuadsArray = new SymbolQuadsArray(data.symbolQuadsArray); this.featureIndex = new FeatureIndex(data.featureIndex, data.rawTileData, this.collisionTile); this.rawTileData = data.rawTileData; this.buckets = unserializeBuckets(data.buckets, style); @@ -97,6 +101,8 @@ Tile.prototype = { } this.collisionBoxArray = null; + this.symbolQuadsArray = null; + this.symbolInstancesArray = null; this.collisionTile = null; this.featureIndex = null; this.rawTileData = null; diff --git a/js/source/worker_tile.js b/js/source/worker_tile.js index 918a359192c..59a28ed4bf8 100644 --- a/js/source/worker_tile.js +++ b/js/source/worker_tile.js @@ -6,6 +6,8 @@ var Bucket = require('../data/bucket'); var CollisionBoxArray = require('../symbol/collision_box'); var DictionaryCoder = require('../util/dictionary_coder'); var util = require('../util/util'); +var SymbolInstancesArray = require('../symbol/symbol_instances'); +var SymbolQuadsArray = require('../symbol/symbol_quads'); module.exports = WorkerTile; @@ -27,6 +29,8 @@ WorkerTile.prototype.parse = function(data, layerFamilies, actor, rawTileData, c this.data = data; this.collisionBoxArray = new CollisionBoxArray(); + this.symbolInstancesArray = new SymbolInstancesArray(); + this.symbolQuadsArray = new SymbolQuadsArray(); var collisionTile = new CollisionTile(this.angle, this.pitch, this.collisionBoxArray); var featureIndex = new FeatureIndex(this.coord, this.overscaling, collisionTile, data.layers); var sourceLayerCoder = new DictionaryCoder(data.layers ? Object.keys(data.layers).sort() : ['_geojsonTileLayer']); @@ -61,6 +65,8 @@ WorkerTile.prototype.parse = function(data, layerFamilies, actor, rawTileData, c overscaling: this.overscaling, showCollisionBoxes: this.showCollisionBoxes, collisionBoxArray: this.collisionBoxArray, + symbolQuadsArray: this.symbolQuadsArray, + symbolInstancesArray: this.symbolInstancesArray, sourceLayerIndex: sourceLayerCoder.encode(layer.sourceLayer || '_geojsonTileLayer') }); bucket.createFilter(); @@ -207,6 +213,8 @@ WorkerTile.prototype.parse = function(data, layerFamilies, actor, rawTileData, c var featureIndex_ = featureIndex.serialize(); var collisionTile_ = collisionTile.serialize(); var collisionBoxArray = tile.collisionBoxArray.serialize(); + var symbolInstancesArray = tile.symbolInstancesArray.serialize(); + var symbolQuadsArray = tile.symbolQuadsArray.serialize(); var transferables = [rawTileData].concat(featureIndex_.transferables).concat(collisionTile_.transferables); var nonEmptyBuckets = buckets.filter(isBucketEmpty); @@ -217,6 +225,8 @@ WorkerTile.prototype.parse = function(data, layerFamilies, actor, rawTileData, c featureIndex: featureIndex_.data, collisionTile: collisionTile_.data, collisionBoxArray: collisionBoxArray, + symbolInstancesArray: symbolInstancesArray, + symbolQuadsArray: symbolQuadsArray, rawTileData: rawTileData }, getTransferables(nonEmptyBuckets).concat(transferables)); } diff --git a/js/symbol/symbol_instances.js b/js/symbol/symbol_instances.js new file mode 100644 index 00000000000..5250f0f8adf --- /dev/null +++ b/js/symbol/symbol_instances.js @@ -0,0 +1,37 @@ +'use strict'; + +var StructArrayType = require('../util/struct_array'); +var util = require('../util/util'); +var Point = require('point-geometry'); + +/* +* +* A StructArray implementation of symbolInstances from data/bucket/symbol_bucket.js +* this will allow symbolInstances to be transferred between the worker and main threads +* +* @class SymbolInstanceArray +* @private +*/ + +var SymbolInstancesArray = module.exports = new StructArrayType({ + members: [ + // the indices of the glyph quads applicable to this particular symbol instance + { type: 'Int16', name: 'glyphQuadsStart' }, + { type: 'Int16', name: 'glyphQuadsEnd' }, + { type: 'Int16', name: 'iconQuadIndex' }, + + // each symbolInstance is centered around the anchor point + { type: 'Int16', name: 'anchorPointX' }, + { type: 'Int16', name: 'anchorPointY' }, + + // index + {type: 'Int8', name: 'index'} + ] +}); + +util.extendAll(SymbolInstancesArray.prototype.StructType.prototype, { + get anchorPoint() { + return new Point(this.anchorPointX, this.anchorPointY); + } +}); + diff --git a/js/symbol/symbol_quads.js b/js/symbol/symbol_quads.js new file mode 100644 index 00000000000..f75b46e3b88 --- /dev/null +++ b/js/symbol/symbol_quads.js @@ -0,0 +1,56 @@ +'use strict'; + +var StructArrayType = require('../util/struct_array'); +var util = require('../util/util'); +var Point = require('point-geometry'); + +// notes from ansis on slack: +// it would be best if they are added to a buffer in advance so that they are only created once. There would be a separate buffer with all the individual collision boxes and then SymbolInstance would store the beginning and end indexes of a feature's collisionboxes. CollisionFeature wouldn't really exist as a standalone thing, it would just be a range of boxes in the big collision box buffer + +/* +* +* A StructArray implementation of glyphQuad from symbol/quads +* this will allow glyph quads to be transferred between the worker and main threads along with the rest of +* the symbolInstances +* +* @class SymbolQuadsArray +* @private +*/ + +var SymbolQuadsArray = module.exports = new StructArrayType({ + members: [ + // the quad is centered around the anchor point + { type: 'Int16', name: 'anchorPointX' }, + { type: 'Int16', name: 'anchorPointY' }, + + // the offsets of the tl (top-left), tr, bl, br corners from the anchor point + // do these need to be floats? + { type: 'Int16', name: 'tlX' }, + { type: 'Int16', name: 'tlY' }, + { type: 'Int16', name: 'trX' }, + { type: 'Int16', name: 'trY' }, + { type: 'Int16', name: 'blX' }, + { type: 'Int16', name: 'blY' }, + { type: 'Int16', name: 'brX' }, + { type: 'Int16', name: 'brY' }, + + // texture coordinates (height, width, x, and y) + { type: 'Int16', name: 'texH' }, + { type: 'Int16', name: 'texW' }, + { type: 'Int16', name: 'texX' }, + { type: 'Int16', name: 'texY' }, + + //the angle of the label at it's center, not the angle of this quad. + { type: 'Float32', name: 'angle' }, + + // quad is only valid for scales < maxScale && scale > minScale. + { type: 'Float32', name: 'maxScale' }, + { type: 'Float32', name: 'minScale' } + ] +}); + +util.extendAll(SymbolQuadsArray.prototype.StructType.prototype, { + get anchorPoint() { + return new Point(this.anchorPointX, this.anchorPointY); + } +});